﻿///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2023, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Область ПрограммныйИнтерфейс

////////////////////////////////////////////////////////////////////////////////
// Команды работы с файлами

// Открывает файл для просмотра или редактирования.
// Если файл открывается для просмотра, тогда получает файл в рабочий каталог пользователя,
// при этом ищет файл в рабочем каталоге и предлагает открыть существующий или получить файл с сервера.
// Если файл открывается для редактирования, тогда открывает файл в рабочем каталоге (если есть) или
// получает его с сервера.
//
// Параметры:
//  ДанныеФайла       - см. РаботаСФайлами.ДанныеФайла.
//  ДляРедактирования - Булево - Истина, если файл открывается для редактирования, иначе Ложь.
//
Процедура ОткрытьФайл(Знач ДанныеФайла, Знач ДляРедактирования = Ложь) Экспорт
	
	Если ДляРедактирования Тогда
		РаботаСФайламиСлужебныйКлиент.РедактироватьФайл(Неопределено, ДанныеФайла);
	Иначе
		РаботаСФайламиСлужебныйКлиент.ОткрытьФайлСОповещением(Неопределено, ДанныеФайла, , ДляРедактирования); 
	КонецЕсли;
	
КонецПроцедуры

// Открывает в стандартной программе просмотра (проводнике) каталог на компьютере,
// в котором размещен указанный файл.
//
// Параметры:
//  ДанныеФайла - см. РаботаСФайлами.ДанныеФайла.
//
Процедура ОткрытьКаталогФайла(ДанныеФайла) Экспорт
	
	РаботаСФайламиСлужебныйКлиент.КаталогФайла(Неопределено, ДанныеФайла);
	
КонецПроцедуры

// Открывает диалог выбора файлов для помещения в программу одного или нескольких файлов.
// При этом проверяются необходимые условия:
// - размер файла не превышает максимально допустимого,
// - файл имеет допустимое расширение,
// - имеется свободное место в томе (при хранении файлов в томах),
// - прочие условия.
//
// Параметры:
//  ВладелецФайла      - ОпределяемыйТип.ВладелецПрисоединенныхФайлов - папка файлов или объект, к которому
//                       требуется прикрепить добавляемый файл.
//  ИдентификаторФормы - УникальныйИдентификатор - уникальный идентификатор формы, во временное хранилище
//                       которой будет помещен файл.
//  Фильтр             - Строка - фильтр выбираемого файла, например, картинки для номенклатуры.
//  ГруппаФайлов       - ОпределяемыйТип.ПрисоединенныйФайл - группа справочника с файлами, в которую будет 
//                       добавлен новый файл.
//  ОбработчикРезультата - ОписаниеОповещения - описание процедуры, вызов которой будет произведен
//                         после добавления файлов со следующими параметрами:
//        Результат - Массив - ссылки на добавленные файлы. Если файлы не были добавлены, пустой массив.
//        ДополнительныеПараметры - Произвольный - значение, указанное при создании описания оповещения.
//
Процедура ДобавитьФайлы(Знач ВладелецФайла, Знач ИдентификаторФормы, Знач Фильтр = "", ГруппаФайлов = Неопределено,
	ОбработчикРезультата = Неопределено) Экспорт
	
	Если Не ЗначениеЗаполнено(ВладелецФайла) Тогда
		Шаблон = НСтр("ru = 'Не задано значение параметра %1 в %2.'");
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Шаблон, "ВладелецФайла", 
			"РаботаСФайламиКлиент.ДобавитьФайлы");
	КонецЕсли;
	
	Параметры = Новый Структура;
	Параметры.Вставить("ВладелецФайла",        ВладелецФайла);
	Параметры.Вставить("ИдентификаторФормы",   ИдентификаторФормы);
	Параметры.Вставить("Фильтр",               Фильтр);
	Параметры.Вставить("ГруппаФайлов",         ГруппаФайлов);
	Параметры.Вставить("ОбработчикРезультата", ОбработчикРезультата);
	
	ОписаниеОповещения = Новый ОписаниеОповещения("ДобавитьФайлыРасширениеПредложено", РаботаСФайламиСлужебныйКлиент, Параметры);
	РаботаСФайламиСлужебныйКлиент.ПоказатьВопросОбУстановкеРасширенияРаботыСФайлами(ОписаниеОповещения);
	
КонецПроцедуры

// Открывает диалог выбора файлов для помещения в программу одного выбранного файла.
//
// Параметры:
//   ОбработчикРезультата - ОписаниеОповещения - содержит описание процедуры, вызов которой будет произведен
//                        после добавления файла со следующими параметрами:
//                    * Результат - Структура:
//                       ** ФайлСсылка - ОпределяемыйТип.ПрисоединенныйФайл - ссылка на элемент справочника с файлом,
//                                     если он был добавлен, иначе Неопределено.
//                       ** ФайлДобавлен - Булево - Истина, если файл добавлен.
//                       ** ТекстОшибки  - Строка - текст ошибки, если файл не был добавлен.
//                    * ДополнительныеПараметры - Произвольный - значение, указанное при создании объекта оповещения.
//
//   ВладелецФайла - ОпределяемыйТип.ВладелецПрисоединенныхФайлов - папка файлов или объект, к которому
//                 требуется прикрепить добавляемый файл.
//   ФормаВладелец - ФормаКлиентскогоПриложения - форма, из которой вызвано создание файла.
//   РежимСоздания - Неопределено
//                 - Число - режим создания файла:
//                 - Неопределено - показать диалог выбора режима создания файла.
//                 - Число - создать файл указанным способом:
//                           1 - из шаблона (копированием другого файла);
//                           2 - с компьютера (из файловой системы);
//                           3 - со сканера.
//
//   ПараметрыДобавления - Структура - дополнительные параметры добавления файлов:
//     * МаксимальныйРазмер  - Число - ограничение на размер файла (в мегабайтах), загружаемого из файловой системы.
//                           Если принимает значение 0, проверка размера не проводится. Свойство игнорируется,
//                           если принимает значение больше, чем указано в константе МаксимальныйРазмерФайла.
//     * ФильтрДиалогаВыбора - Строка - фильтр, устанавливаемый в диалог выбора при добавлении файла.
//                           Формат см. в свойстве Фильтр объекта ДиалогВыбораФайла в синтакс-помощнике.
//     * НеОткрыватьКарточку - Булево - действие после создания. Если принимает значение Истина, карточка файла
//                           не будет открыта после создания, иначе - карточку файла будет открыта.
//
Процедура ДобавитьФайл(ОбработчикРезультата, ВладелецФайла, ФормаВладелец, РежимСоздания = Неопределено, 
	ПараметрыДобавления = Неопределено) Экспорт
	
	Если Не ЗначениеЗаполнено(ВладелецФайла) Тогда
		Шаблон = НСтр("ru = 'Не задано значение параметра %1 в %2.'");
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Шаблон, "ВладелецФайла",
			"РаботаСФайламиКлиент.ДобавитьФайл");
	КонецЕсли;
	
	ПараметрыВыполнения = Новый Структура;
	Если ПараметрыДобавления = Неопределено
		Или ТипЗнч(ПараметрыДобавления) = Тип("Булево") Тогда
		
		ПараметрыВыполнения.Вставить("МаксимальныйРазмер" , 0);
		ПараметрыВыполнения.Вставить("НеОткрыватьКарточку", ?(ПараметрыДобавления = Неопределено, Ложь, ПараметрыДобавления));
		ПараметрыВыполнения.Вставить("ФильтрДиалогаВыбора",  
			СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Все файлы (%1)|%1'"), ПолучитьМаскуВсеФайлы()));
		
	Иначе
		ПараметрыВыполнения.Вставить("МаксимальныйРазмер" , ПараметрыДобавления.МаксимальныйРазмер);
		ПараметрыВыполнения.Вставить("НеОткрыватьКарточку", ПараметрыДобавления.НеОткрыватьКарточку);
		ПараметрыВыполнения.Вставить("ФильтрДиалогаВыбора", ПараметрыДобавления.ФильтрДиалогаВыбора);
	КонецЕсли;
	
	Если РежимСоздания = Неопределено Тогда
		РаботаСФайламиСлужебныйКлиент.ДобавитьФайл(ОбработчикРезультата, ВладелецФайла, ФормаВладелец, , ПараметрыВыполнения);
	Иначе
		ПараметрыВыполнения.Вставить("ОбработчикРезультата", ОбработчикРезультата);
		ПараметрыВыполнения.Вставить("ВладелецФайла", ВладелецФайла);
		ПараметрыВыполнения.Вставить("ФормаВладелец", ФормаВладелец);
		ПараметрыВыполнения.Вставить("ТолькоОдинФайл", Истина);
		РаботаСФайламиСлужебныйКлиент.ДобавитьПослеВыбораРежимаСоздания(РежимСоздания, ПараметрыВыполнения);
	КонецЕсли;
	
КонецПроцедуры

// Открывает форму для настройки параметров рабочего каталога из персональных настроек пользователя программы.
// Рабочий каталог - папка на персональном компьютере пользователя, в которой временно хранятся файлы,
// полученные из программы для просмотра или редактирования.
//
Процедура ОткрытьФормуНастройкиРабочегоКаталога() Экспорт
	
	ОткрытьФорму("ОбщаяФорма.НастройкаРабочегоКаталога");
	
КонецПроцедуры

// Показать предупреждение перед закрытием формы объекта в том случае,
// если у пользователя остались захваченные файлы, присоединенные к этому объекту.
// Вызывается из события ПередЗакрытием форм с файлами.
//
// Если захваченные файлы остались, то в параметре Отказ устанавливается значение Истина,
// а пользователю задается вопрос. Если пользователь ответил утвердительно, то форма закрывается.
//
// Параметры:
//   Форма            - ФормаКлиентскогоПриложения - форма, в которой редактируется файл.
//   Отказ            - Булево - параметр события ПередЗакрытием.
//   ЗавершениеРаботы - Булево - признак того, что форма закрывается в процессе завершения работы приложения.
//   ВладелецФайлов   - ОпределяемыйТип.ВладелецПрисоединенныхФайлов - папка файлов или объект, к которому присоединены
//                      файлы.
//   ИмяРеквизита     - Строка - имя реквизита типа Булево, в котором хранится признак того,
//                      что вопрос уже выводился.
//
// Пример:
//
//	&НаКлиенте
//	Процедура ПередЗакрытием(Отказ, ЗавершениеРаботы, ТекстПредупреждения, СтандартнаяОбработка)
//		РаботаСФайламиКлиент.ПоказатьПодтверждениеЗакрытияФормыСФайлами(ЭтотОбъект, Отказ, ЗавершениеРаботы, Объект.Ссылка);
//	КонецПроцедуры
//
Процедура ПоказатьПодтверждениеЗакрытияФормыСФайлами(Форма, Отказ, ЗавершениеРаботы, ВладелецФайлов,
	ИмяРеквизита = "МожноЗакрытьФормуСФайлами") Экспорт
	
	ИмяПроцедуры = "РаботаСФайламиКлиент.ПоказатьПодтверждениеЗакрытияФормыСФайлами";
	ОбщегоНазначенияКлиентСервер.ПроверитьПараметр(ИмяПроцедуры, "Форма", Форма, Тип("ФормаКлиентскогоПриложения"));
	ОбщегоНазначенияКлиентСервер.ПроверитьПараметр(ИмяПроцедуры, "Отказ", Отказ, Тип("Булево"));
	ОбщегоНазначенияКлиентСервер.ПроверитьПараметр(ИмяПроцедуры, "ЗавершениеРаботы", ЗавершениеРаботы, Тип("Булево"));
	ОбщегоНазначенияКлиентСервер.ПроверитьПараметр(ИмяПроцедуры, "ИмяРеквизита", ИмяРеквизита, Тип("Строка"));
		
	Если Форма[ИмяРеквизита] Тогда
		Возврат;
	КонецЕсли;
	
	Если ЗавершениеРаботы Тогда
		Возврат;
	КонецЕсли;
	
	Количество = РаботаСФайламиСлужебныйВызовСервера.КоличествоФайловЗанятыхТекущимПользователем(ВладелецФайлов);
	Если Количество = 0 Тогда
		Возврат;
	КонецЕсли;
	
	Отказ = Истина;
	
	ТекстВопроса = НСтр("ru = 'Один или несколько файлов заняты для редактирования.
	                          |
	                          |Продолжить?'");
	ОбщегоНазначенияКлиент.ПоказатьПодтверждениеЗакрытияПроизвольнойФормы(Форма, Отказ, ЗавершениеРаботы, ТекстВопроса, ИмяРеквизита);
	
КонецПроцедуры

// Открывает форму нового файла с копией указанного файла.
//
// Параметры:
//  ВладелецФайла - ОпределяемыйТип.ВладелецПрисоединенныхФайлов - папка файлов или объект, к которому присоединен файл.
//  ФайлОснование - ОпределяемыйТип.ПрисоединенныйФайл - копируемый файл.
//  ДополнительныеПараметры - Структура - параметры открытия формы:
//    * ИмяСправочникаХранилищаФайлов - Строка - определяет справочник для хранения копии файла.
//  ОписаниеОповещенияОЗакрытии - ОписаниеОповещения - описание процедуры, которая будет вызвана при закрытии формы
//                                со следующими параметрами:
//                                <РезультатЗакрытия> - значение, переданное при вызове Закрыть() открываемой формы;
//                                <ДополнительныеПараметры> - значение, указанное при создании
//                                ОписаниеОповещенияОЗакрытии.
//                                Если параметр не указан, то по завершению никакая процедура вызвана не будет.
//
Процедура СкопироватьФайл(ВладелецФайла, ФайлОснование, ДополнительныеПараметры = Неопределено,
	ОписаниеОповещенияОЗакрытии = Неопределено) Экспорт
	
	Если Не ЗначениеЗаполнено(ВладелецФайла) Тогда
		Шаблон = НСтр("ru = 'Не задано значение параметра %1 в %2.'");
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Шаблон, "ВладелецФайла",
			"РаботаСФайламиКлиент.СкопироватьФайл");
	КонецЕсли;
	
	ЭтоФайлы = ТипЗнч(ФайлОснование) = Тип("СправочникСсылка.Файлы");
	
	ПараметрыФормы = Новый Структура;
	Если ТипЗнч(ДополнительныеПараметры) = Тип("Структура") Тогда
		ПараметрыФормы = ОбщегоНазначенияКлиент.СкопироватьРекурсивно(ДополнительныеПараметры);
		ИмяСправочникаХранилищаФайлов = Неопределено;
		Если ДополнительныеПараметры.Свойство("ИмяСправочникаХранилищаФайлов", ИмяСправочникаХранилищаФайлов) Тогда
			ЭтоФайлы = (ИмяСправочникаХранилищаФайлов = "Файлы");
		КонецЕсли;
	КонецЕсли;
	
	ПараметрыФормы.Вставить("ЗначениеКопирования", ФайлОснование);
	ПараметрыФормы.Вставить("ВладелецФайла", ВладелецФайла);
	Если ЭтоФайлы Тогда
		ОткрытьФорму("Справочник.Файлы.ФормаОбъекта", ПараметрыФормы,,,,, ОписаниеОповещенияОЗакрытии);
	Иначе
		ОткрытьФорму("Обработка.РаботаСФайлами.Форма.ПрисоединенныйФайл", ПараметрыФормы,,,,, ОписаниеОповещенияОЗакрытии);
	КонецЕсли;
	
КонецПроцедуры

// Открывает список электронных подписей файла и предлагает выбрать подписи
// для сохранения вместе с файлом по выбранному пользователем пути.
// Имя файл подписи формируется из имени файла и автора подписи с расширением "p7s".
//
// При отсутствии в конфигурации подсистемы "Электронная подпись" сохранение файла не будет выполнено.
//
// Параметры:
//  ПрисоединенныйФайл - ОпределяемыйТип.ПрисоединенныйФайл - ссылка на элемент справочника с файлом.
//  ИдентификаторФормы - УникальныйИдентификатор  - уникальный идентификатор формы, который используется для блокировки файл.
//
Процедура СохранитьВместеСЭП(Знач ПрисоединенныйФайл, Знач ИдентификаторФормы) Экспорт
	
	Если Не ОбщегоНазначенияКлиент.ПодсистемаСуществует("СтандартныеПодсистемы.ЭлектроннаяПодпись") Тогда
		Возврат;
	КонецЕсли;
	
	ДанныеФайла = РаботаСФайламиСлужебныйВызовСервера.ДанныеФайлаДляСохранения(ПрисоединенныйФайл);
	
	ПараметрыВыполнения = Новый Структура;
	ПараметрыВыполнения.Вставить("ПрисоединенныйФайл", ПрисоединенныйФайл);
	ПараметрыВыполнения.Вставить("ДанныеФайла",        ДанныеФайла);
	ПараметрыВыполнения.Вставить("ИдентификаторФормы", ИдентификаторФормы);
	
	ОписаниеДанных = Новый Структура;
	ОписаниеДанных.Вставить("ЗаголовокДанных",     НСтр("ru = 'Файл'"));
	ОписаниеДанных.Вставить("ПоказатьКомментарий", Истина);
	ОписаниеДанных.Вставить("Представление",       ПараметрыВыполнения.ДанныеФайла.Ссылка);
	ОписаниеДанных.Вставить("Объект",              ПрисоединенныйФайл);
	
	ОписаниеДанных.Вставить("Данные",
		Новый ОписаниеОповещения("ПриСохраненииДанныхФайла", РаботаСФайламиСлужебныйКлиент, ПараметрыВыполнения));
	
	МодульЭлектроннаяПодписьКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("ЭлектроннаяПодписьКлиент");
	МодульЭлектроннаяПодписьКлиент.СохранитьДанныеВместеСПодписью(ОписаниеДанных);
	
КонецПроцедуры

// Открывает диалог сохранения файл, где пользователь может определить путь и имя для сохранения файла.
//
// Параметры:
//   ДанныеФайла           - см. РаботаСФайлами.ДанныеФайла.
//   ОбработчикЗавершения  - ОписаниеОповещения
//                         - Неопределено - описание процедуры, которая
//                           будет вызвана после завершения со следующими параметрами:
//      ПутьКФайлу              - Строка - полный путь к сохраненному файлу.
//      ДополнительныеПараметры - Произвольный - значение, которое было указано при создании объекта ОписаниеОповещения.
//
Процедура СохранитьФайлКак(Знач ДанныеФайла, ОбработчикЗавершения = Неопределено) Экспорт
	
	Оповещение = Новый ОписаниеОповещения("СохранитьФайлКакПослеСохранения",
		РаботаСФайламиСлужебныйКлиент, ОбработчикЗавершения);
	
	РаботаСФайламиСлужебныйКлиент.СохранитьКак(Оповещение, ДанныеФайла, Неопределено);
	
КонецПроцедуры

// Открывает форму выбора файлов.
// Используется в обработчике выбора для переопределения стандартного поведения.
//
// Параметры:
//  ВладелецФайлов - ОпределяемыйТип.ВладелецПрисоединенныхФайлов - папка файлов или объект,
//                   к которому прикреплены выбираемые файлы.
//  ЭлементФормы   - ТаблицаФормы
//                 - ПолеФормы - элемент формы, которому будет отправлено
//                   оповещение о выборе.
//  СтандартнаяОбработка - Булево - возвращаемое значение. Всегда устанавливается в Ложь.
//  ОписаниеОповещенияОВыборе - ОписаниеОповещения - описание процедуры, которая будет вызвана при закрытии формы 
//                                                   со следующими параметрами:
//    ЗначениеВыбора - ОпределяемыйТип.ПрисоединенныйФайл
//                   - Неопределено - если произошел выбор, тогда будет 
//                     возвращено значение выбора. Иначе - Неопределено.
//    ДополнительныеПараметры - Произвольный - значение, указанное при создании ОписаниеОповещенияОЗакрытии.
//
Процедура ОткрытьФормуВыбораФайлов(Знач ВладелецФайлов, Знач ЭлементФормы, СтандартнаяОбработка = Ложь,
	ОписаниеОповещенияОВыборе = Неопределено) Экспорт
	
	СтандартнаяОбработка = Ложь;

	Если ВладелецФайлов.Пустая() Тогда
		ОбработчикОповещенияОЗакрытии = Новый ОписаниеОповещения("ВопросОНеобходимостиЗаписиПослеЗавершения", ЭтотОбъект);
		ПоказатьВопрос(ОбработчикОповещенияОЗакрытии,
			НСтр("ru = 'Данные еще не записаны. 
				|Переход к ""Присоединенные файлы"" возможен только после записи данных.'"),
				РежимДиалогаВопрос.ОК);
	Иначе
		ПараметрыФормы = Новый Структура;
		ПараметрыФормы.Вставить("РежимВыбора", Истина);
		ПараметрыФормы.Вставить("ВладелецФайла", ВладелецФайлов);
		ОткрытьФорму("Обработка.РаботаСФайлами.Форма.ПрисоединенныеФайлы", ПараметрыФормы, ЭлементФормы,,,,
						?(ОписаниеОповещенияОВыборе <> Неопределено, ОписаниеОповещенияОВыборе, Неопределено));
	КонецЕсли;
	
КонецПроцедуры

// Открывает форму списка файлов.
//
// Параметры:
//  ВладелецФайлов - ОпределяемыйТип.ВладелецПрисоединенныхФайлов - папка файлов или объект,
//                   к которому прикреплены выбираемые файлы.
//
Процедура ОткрытьФормуСпискаФайлов(Знач ВладелецФайлов) Экспорт
	
	ПараметрыФормы = Новый Структура();
	ПараметрыФормы.Вставить("ВладелецФайла", ВладелецФайлов);
	ПараметрыФормы.Вставить("СкрыватьВладельца", Ложь);
	ОткрытьФорму("Обработка.РаботаСФайлами.Форма.ПрисоединенныеФайлы", ПараметрыФормы);
	
КонецПроцедуры

// Открывает форму файла.
// Может использоваться как обработчик открытия файла.
//
// Параметры:
//  ПрисоединенныйФайл      - ОпределяемыйТип.ПрисоединенныйФайл - ссылка на элемент справочника с файлом.
//  СтандартнаяОбработка    - Булево - возвращаемое значение. Всегда устанавливается в Ложь.
//  ДополнительныеПараметры - Структура - параметры открытия формы.
//  ОписаниеОповещенияОЗакрытии - ОписаниеОповещения - описание процедуры, которая будет вызвана при закрытии формы,
//                                со следующими параметрами:
//                                <РезультатЗакрытия> - значение, переданное при вызове Закрыть() открываемой формы;
//                                <ДополнительныеПараметры> - значение, указанное при создании 
//                                ОписаниеОповещенияОЗакрытии. 
//                                Если параметр не указан, то по завершении никакая процедура вызвана не будет.
//
Процедура ОткрытьФормуФайла(Знач ПрисоединенныйФайл, СтандартнаяОбработка = Ложь, ДополнительныеПараметры = Неопределено, 
	ОписаниеОповещенияОЗакрытии = Неопределено) Экспорт
	
	СтандартнаяОбработка = Ложь;
	
	Если Не ЗначениеЗаполнено(ПрисоединенныйФайл) Тогда
		Возврат;
	КонецЕсли;
	
	ПараметрыФормы = Новый Структура;
	Если ТипЗнч(ДополнительныеПараметры) = Тип("Структура") Тогда
		ПараметрыФормы = ОбщегоНазначенияКлиент.СкопироватьРекурсивно(ДополнительныеПараметры);
	КонецЕсли;	
	Если ТипЗнч(ПрисоединенныйФайл) = Тип("СправочникСсылка.Файлы") Тогда
		ПараметрыФормы.Вставить("Ключ", ПрисоединенныйФайл);
		ОткрытьФорму("Справочник.Файлы.ФормаОбъекта", ПараметрыФормы,,,,, ОписаниеОповещенияОЗакрытии);
	Иначе	
		ПараметрыФормы.Вставить("ПрисоединенныйФайл", ПрисоединенныйФайл);
		ОткрытьФорму("Обработка.РаботаСФайлами.Форма.ПрисоединенныйФайл", ПараметрыФормы,, ПрисоединенныйФайл,,, ОписаниеОповещенияОЗакрытии);
	КонецЕсли;
	
КонецПроцедуры

// Выполняет печать файлов на принтер.
//
// Параметры:
//  Файлы              - ОпределяемыйТип.ПрисоединенныйФайл
//                     - Массив из ОпределяемыйТип.ПрисоединенныйФайл
//  ИдентификаторФормы - УникальныйИдентификатор - уникальный идентификатор формы, во временное хранилище
//                       которой будет помещен файл.
//
Процедура НапечататьФайлы(Знач Файлы, ИдентификаторФормы = Неопределено) Экспорт
	
	Если ТипЗнч(Файлы) <> Тип("Массив") Тогда
		Файлы = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Файлы);
	КонецЕсли;
	
	ПараметрыВыполнения = Новый Структура;
	ПараметрыВыполнения.Вставить("НомерФайла",   0);
	ПараметрыВыполнения.Вставить("ДанныеФайлов", Файлы);
	ПараметрыВыполнения.Вставить("ДанныеФайла",  Файлы);
	ПараметрыВыполнения.Вставить("УникальныйИдентификатор", ИдентификаторФормы);
	НапечататьФайлыВыполнение(Неопределено, ПараметрыВыполнения);
	
КонецПроцедуры

// Выполняет подписание файла электронной подписью.
// При отсутствии подсистемы "Электронная подпись" будет показано предупреждение
// о невозможности добавления электронной подписи.
//
// Параметры:
//  ПрисоединенныйФайл      - ОпределяемыйТип.ПрисоединенныйФайл - ссылка на элемент справочника с файлом.
//                          - Массив из ОпределяемыйТип.ПрисоединенныйФайл
//  ИдентификаторФормы      - УникальныйИдентификатор - уникальный идентификатор формы,
//                            который используется для блокировки файла.
//  ДополнительныеПараметры - Неопределено - стандартное поведение (см. ниже).
//                          - Структура:
//       * ДанныеФайла            - см. РаботаСФайлами.ДанныеФайла
//                                - Массив из см. РаботаСФайлами.ДанныеФайла
//       * ОбработкаРезультата    - ОписаниеОповещения - при вызове передается значение типа Булево,
//                                  если Истина - файл успешно подписан, иначе не подписан,
//                                  если свойства нет, оповещение не будет вызвано.
//  ПараметрыПодписи         - см. ЭлектроннаяПодписьКлиент.НовыйТипПодписи
//
Процедура ПодписатьФайл(ПрисоединенныйФайл, ИдентификаторФормы, ДополнительныеПараметры = Неопределено,
	ПараметрыПодписи = Неопределено) Экспорт
	
	Если Не ЗначениеЗаполнено(ПрисоединенныйФайл) Тогда
		ПоказатьПредупреждение(, НСтр("ru = 'Не выбран файл, который нужно подписать.'"));
		Возврат;
	КонецЕсли;
	
	Если Не ОбщегоНазначенияКлиент.ПодсистемаСуществует("СтандартныеПодсистемы.ЭлектроннаяПодпись") Тогда
		ПоказатьПредупреждение(, НСтр("ru = 'Добавление электронных подписей не поддерживается.'"));
		Возврат;
	КонецЕсли;
	
	МодульЭлектроннаяПодписьКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("ЭлектроннаяПодписьКлиент");
	
	Если Не МодульЭлектроннаяПодписьКлиент.ИспользоватьЭлектронныеПодписи() Тогда
		ПоказатьПредупреждение(,
			НСтр("ru = 'Чтобы добавить электронную подпись, включите
			           |в настройках программы использование электронных подписей.'"));
		Возврат;
	КонецЕсли;
	
	Если ДополнительныеПараметры = Неопределено Тогда
		ДополнительныеПараметры = Новый Структура;
	КонецЕсли;
	
	Если Не ДополнительныеПараметры.Свойство("ДанныеФайла") Тогда
		ДополнительныеПараметры.Вставить("ДанныеФайла", РаботаСФайламиСлужебныйВызовСервера.ДанныеФайловДляПодписания(
			ПрисоединенныйФайл, ИдентификаторФормы));
	КонецЕсли;
	
	ОбработкаРезультата = Неопределено;
	ДополнительныеПараметры.Свойство("ОбработкаРезультата", ОбработкаРезультата);
	
	РаботаСФайламиСлужебныйКлиент.ПодписатьФайл(ПрисоединенныйФайл,
		ДополнительныеПараметры.ДанныеФайла, ИдентификаторФормы, ОбработкаРезультата, Неопределено, ПараметрыПодписи);
	
КонецПроцедуры

// Возвращает структурированную информацию о файле. Используется в различных командах работы с файлами
// и как значение параметра ДанныеФайла других процедур и функций.
//
// Параметры:
//   ФайлСсылка - ОпределяемыйТип.ПрисоединенныйФайл - ссылка на элемент справочника с файлом.
//   ИдентификаторФормы             - УникальныйИдентификатор - уникальный идентификатор формы, во временное хранилище
//                                     которой надо поместить файл и вернуть адрес в свойстве СсылкаНаДвоичныеДанныеФайла.
//   ПолучатьСсылкуНаДвоичныеДанные - Булево - если передать Ложь, то ссылка на двоичные данные в СсылкаНаДвоичныеДанныеФайла
//                                     не будет получена, что существенно ускорит выполнение для больших двоичных данных.
//   ДляРедактирования              - Булево - если указать Истина, то файл будет захвачен для редактирования.
//
// Возвращаемое значение:
//   см. РаботаСФайлами.ДанныеФайла
//
Функция ДанныеФайла(Знач ФайлСсылка,
                    Знач ИдентификаторФормы = Неопределено,
                    Знач ПолучатьСсылкуНаДвоичныеДанные = Истина,
                    Знач ДляРедактирования = Ложь) Экспорт
	
	Возврат РаботаСФайламиСлужебныйВызовСервера.ПолучитьДанныеФайла(
		ФайлСсылка,
		ИдентификаторФормы,
		ПолучатьСсылкуНаДвоичныеДанные,
		ДляРедактирования);

КонецФункции

// Получает файл из хранилища файлов в рабочий каталог пользователя.
// Аналог интерактивного действия Просмотреть или Редактировать без открытия полученного файла.
// Свойство ТолькоПросмотр полученного файла будет установлено в зависимости от того, захвачен
// файл для редактирования или нет. Если не захвачен - устанавливается только просмотр.
// Если в рабочем каталоге уже существует файл, тогда он будет удален и заменен файлом,
// полученным из хранилища файлов.
//
// Параметры:
//  Оповещение - ОписаниеОповещения - оповещение, которое выполняется после получения файла в
//   рабочий каталог пользователя. В качестве результата возвращается структура со свойствами:
//     ПолноеИмяФайла - Строка - полное имя файла (с путем).
//     ОписаниеОшибки - Строка - текст ошибки, если получить файл не удалось.
//
//  ПрисоединенныйФайл - ОпределяемыйТип.ПрисоединенныйФайл - ссылка на элемент справочника с файлом.
//  ИдентификаторФормы - УникальныйИдентификатор - уникальный идентификатор формы, во временное хранилище
//                       которой будет помещен файл.
//
//  ДополнительныеПараметры - Неопределено - использовать значения по умолчанию.
//                          - Структура - с необязательными свойствами:
//         * ДляРедактирования - Булево    - начальное значение Ложь. Если Истина,
//                                           тогда файл будет захвачен для редактирования.
//         * ДанныеФайла       - Структура - свойства файла, которые можно передать для ускорения,
//                                           если они ранее были получены на клиент с сервера.
//
Процедура ПолучитьПрисоединенныйФайл(Оповещение, ПрисоединенныйФайл, ИдентификаторФормы, ДополнительныеПараметры = Неопределено) Экспорт
	
	РаботаСФайламиСлужебныйКлиент.ПолучитьПрисоединенныйФайл(Оповещение, ПрисоединенныйФайл, ИдентификаторФормы, ДополнительныеПараметры);
	
КонецПроцедуры

// Помещает файл из рабочего каталога пользователя в хранилище файлов.
// Аналог интерактивного действия Закончить редактирование.
//
// Параметры:
//  Оповещение - ОписаниеОповещения - оповещение, которое выполняется после помещения файла в
//   хранилище файлов. В качестве результата возвращается структура со свойством:
//     ОписаниеОшибки - Строка - текст ошибки, если поместить файл не удалось.
//
//  ПрисоединенныйФайл - ОпределяемыйТип.ПрисоединенныйФайл - ссылка на элемент справочника с файлом.
//  ИдентификаторФормы - УникальныйИдентификатор - уникальный идентификатор формы,
//          во временное хранилище которой надо поместить данные и вернуть новый адрес.
//
//  ДополнительныеПараметры - Неопределено - использовать значения по умолчанию.
//                          - Структура - с необязательными свойствами:
//         * ПолноеИмяФайла - Строка - если заполнено, то указанный файл будет помещен в рабочий каталог
//                                     пользователя, а затем в хранилище файлов.
//         * ДанныеФайла    - Структура - свойства файла, которые можно передать для ускорения,
//                                        если они ранее были получены на клиент с сервера.
//
Процедура ПоместитьПрисоединенныйФайл(Оповещение, ПрисоединенныйФайл, ИдентификаторФормы, ДополнительныеПараметры = Неопределено) Экспорт
	
	РаботаСФайламиСлужебныйКлиент.ПоместитьПрисоединенныйФайл(Оповещение, ПрисоединенныйФайл, ИдентификаторФормы, ДополнительныеПараметры);
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Работа со сканером.

// Открывает форму настройки сканирования из пользовательских настроек.
//
Процедура ОткрытьФормуНастройкиСканирования() Экспорт
	
	Если Не РаботаСФайламиСлужебныйКлиент.ДоступноСканирование() Тогда
		ТекстСообщения = НСтр("ru = 'Сканирование возможно в программах для операционных систем Microsoft Windows x86 и х64.'");
		ПоказатьПредупреждение(, ТекстСообщения);
		Возврат;
	КонецЕсли;
	
	Обработчик = Новый ОписаниеОповещения("ОткрытьФормуНастройкиСканированияЗавершение", ЭтотОбъект);
	
	РаботаСФайламиСлужебныйКлиент.ПроинициализироватьКомпоненту(Обработчик, Истина);
		
КонецПроцедуры

// Конструктор параметров параметров конвертации графических документов в PDF.
// 
// Возвращаемое значение:
//  Структура:
//   * ТипРезультата - см. ТипРезультатаКонвертацииИмяФайла
//                   - см. ТипРезультатаКонвертацииДвоичныеДанные
//                   - см. ТипРезультатаКонвертацииПрисоединенныйФайл
//   * ФорматРезультата - Строка - формат результирующего файла "pdf" или "tif"
//   * ИмяФайлаРезультата - см. ТипРезультатаКонвертацииИмяФайла
//   * ИспользоватьImageMagick - Булево - признак использования утилиты ImageMagick
//
Функция ПараметрыКонвертацииГрафическогоДокумента() Экспорт
	
	ПараметрыКонвертации = Новый Структура;
	ПараметрыКонвертации.Вставить("ТипРезультата", ТипРезультатаКонвертацииИмяФайла());
	ПараметрыКонвертации.Вставить("ФорматРезультата", "pdf");
	ПараметрыКонвертации.Вставить("ИмяФайлаРезультата", "");
	
	НастройкиСканированияПользователя = ПолучитьНастройкиСканированияПользователя();
	
	ПараметрыКонвертации.Вставить("ИспользоватьImageMagick", 
		НастройкиСканированияПользователя.ИспользоватьImageMagickДляПреобразованияВPDF);
		
	Возврат ПараметрыКонвертации;
	
КонецФункции

// Возвращает тип результата конвертации в файл на клиенте.
// 
// Возвращаемое значение:
//  Строка
//
Функция ТипРезультатаКонвертацииИмяФайла() Экспорт
	
	Возврат "Файл";
	
КонецФункции

// Возвращает тип результата конвертации в двоичные данные.
// 
// Возвращаемое значение:
//  Строка
//
Функция ТипРезультатаКонвертацииДвоичныеДанные() Экспорт
	
	Возврат "ДвоичныеДанные";
	
КонецФункции

// Обозначает тип результата конвертации в присоединенный файл.
// 
// Возвращаемое значение:
//  Строка
//
Функция ТипРезультатаКонвертацииПрисоединенныйФайл() Экспорт
	
	Возврат "ПрисоединенныйФайл";
	
КонецФункции


// Объединить массив переданных документов в один, с возможностью конвертации.
// 
// Параметры:
//  ОповещениеВозврата - ОписаниеОповещения - процедура, которая будет выполнена после объединения файлов.
//  ОбъектыДляОбъединения - Массив из ДвоичныеДанные, ОпределяемыйТип.ПрисоединенныйФайл, Строка - 
//                          Объекты могут поступать в виде двоичных данных, ссылки на присоединенный файл, пути к файлам
//                          на клиенте.
//  ПараметрыКонвертацииГрафическогоДокумента - см. РаботаСФайламиКлиент.ПараметрыКонвертацииГрафическогоДокумента.
// 
Процедура ОбъединитьВМногостраничныйФайл(ОповещениеВозврата, ОбъектыДляОбъединения, ПараметрыКонвертацииГрафическогоДокумента) Экспорт
	
	Результат = РезультатОбъединенияВМногостраничныйДокумент();
	НастройкиСканированияПользователя = ПолучитьНастройкиСканированияПользователя();
	
	ИспользоватьImageMagick = ПараметрыКонвертацииГрафическогоДокумента.ИспользоватьImageMagick; 
	ПутьКПрограммеКонвертации = НастройкиСканированияПользователя.ПутьКПрограммеКонвертации;
	
		Контекст = Новый Структура;
	Контекст.Вставить("ОповещениеВозврата", ОповещениеВозврата);
	Контекст.Вставить("ОбъектыДляОбъединения", ОбъектыДляОбъединения);
	Контекст.Вставить("ПараметрыКонвертацииГрафическогоДокумента", ПараметрыКонвертацииГрафическогоДокумента);
	Контекст.Вставить("НастройкиСканированияПользователя", НастройкиСканированияПользователя);
	
	Если ОбъектыДляОбъединения.Количество() = 0 Тогда
		Результат.ОписаниеОшибки = НСтр("ru='Не указаны изображения для объединения.'");
		ВыполнитьОбработкуОповещения(ОповещениеВозврата, Результат);
		Возврат;
	ИначеЕсли ИспользоватьImageMagick И Не ЗначениеЗаполнено(ПутьКПрограммеКонвертации) Тогда
		ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru='Не указан путь к программе %1.
		|Объединение многостраничных документов выполняется штатными средствами.'"), "ImageMagick");
		
		ЖурналРегистрацииКлиент.ДобавитьСообщениеДляЖурналаРегистрации(СобытиеЖурналаРегистрации(),
			"Предупреждение", ТекстОшибки,, Истина);
		Контекст.ПараметрыКонвертацииГрафическогоДокумента.ИспользоватьImageMagick = Ложь;
		ОбъединитьВМногостраничныйФайлПродолжение(Контекст);
		Возврат;
	КонецЕсли;
	
#Если Не ВебКлиент И Не МобильныйКлиент Тогда
		
	Если ИспользоватьImageMagick Тогда
		ОповещениеРезультата = Новый ОписаниеОповещения("ПослеПроверкиНаличияПрограммыКонвертации", ЭтотОбъект, Контекст);
		НачатьПроверкуНаличияПрограммыКонвертации(ПутьКПрограммеКонвертации, ОповещениеРезультата);
		Возврат;
	КонецЕсли;
	
	ОбъединитьВМногостраничныйФайлПродолжение(Контекст);
	
#КонецЕсли
КонецПроцедуры

// Конструктор параметров для сканирования.
// 
// Параметры:
//  Заполнить - Булево - заполнять текущими сохраненными для пользователя значениями.
// 
// Возвращаемое значение:
//  Структура:
//   * ПоказыватьДиалог - Булево - признак открытия диалога сканирования (поставляемый драйвером сканера) с возможностью
//                                 настроек разрешения и пр.
//   * ВыбранноеУстройство - Строка - имя сканера.
//   * ФорматКартинки - Строка - формат картинки запрашиваемый у драйвера.
//   * Разрешение - Число - разрешение DPI.
//   * Цветность - Число - принимает значения 0 (черно-белое), 1 (оттенки серого), 2 (цветное).
//   * Поворот - Число - угол поворота в градусах, допустимы значения 0, 90, 180, 270. Не все сканеры поддерживают эту 
//                       настройку.
//   * РазмерБумаги - Число - не все сканеры поддерживают эту настройку. Принимает значения
//     0 - не задано
//     11 - А3
//     1 - А4
//     5 - А5
//     6 - B4
//     2 - B5
//     7 - B6
//     14 - C4
//     15 - C5
//     16 - C6
//     3 - USLetter
//     4 - USLegal
//     10 - USExecutive
//   * КачествоJPG - Число - для формата JPG передается качество (от 1 до 100, 100 - максимальное качество и
//                           максимальный размер).
//   * СжатиеTIFF - Число - сжатие:
//     2 - LZW
//     3 - CCITT3
//     4 - CCITT4
//     5 - RLE
//     6 - без сжатия
//   * ДвустороннееСканирование - Булево - использовать двустороннее сканирование.
//   * СохранятьВPDF - Булево
//   * ИспользоватьImageMagickДляПреобразованияВPDF - Булево
//
Функция ПараметрыСканирования(Заполнить = Ложь) Экспорт
	ПараметрыСканирования = РаботаСФайламиСлужебныйКлиентСервер.ПараметрыСканирования();
	ИдентификаторКлиента = РаботаСФайламиСлужебныйКлиент.ИдентификаторКлиента();
	
	Если Заполнить И ИдентификаторКлиента <> Неопределено Тогда
		РаботаСФайламиСлужебныйВызовСервера.ЗаполнитьНастройкиСканирования(ПараметрыСканирования, ИдентификаторКлиента);
	КонецЕсли;
	Возврат ПараметрыСканирования;
КонецФункции

// Конструктор параметров добавления со сканера.
// 
// Возвращаемое значение:
//  Структура:
//    * ОбработчикРезультата - Неопределено, ОписаниеОповещения - оповещение, которое будет вызвано после получения изображений.
//    * ВладелецФайла - Неопределено, ОпределяемыйТип.ВладелецФайлов - владелец файла, для получения изображений в
//                                                                     присоединенные файлы.
//    * ФормаВладелец - Неопределено, Форма - форма из которой вызывается добавление файла.
//    * НеОткрыватьКарточкуПослеСозданияИзФайла - Булево - для режима создания присоединенных файлов.
//    * ЭтоФайл - Булево
//    * ТипРезультата - см. ТипРезультатаКонвертацииИмяФайла 
//                    - см. ТипРезультатаКонвертацииДвоичныеДанные
//                    - см. ТипРезультатаКонвертацииПрисоединенныйФайл
//    * ТолькоОдинФайл - Булево - сканировать только одно изображение.
//
Функция ПараметрыДобавленияСоСканера() Экспорт
	ПараметрыДобавления = Новый Структура;
	ПараметрыДобавления.Вставить("ОбработчикРезультата", Неопределено);
	ПараметрыДобавления.Вставить("ВладелецФайла", Неопределено);
	ПараметрыДобавления.Вставить("ФормаВладелец", Неопределено);
	ПараметрыДобавления.Вставить("НеОткрыватьКарточкуПослеСозданияИзФайла", Истина);
	ПараметрыДобавления.Вставить("ЭтоФайл", Истина);
	ПараметрыДобавления.Вставить("ТипРезультата", ТипРезультатаКонвертацииПрисоединенныйФайл());
	ПараметрыДобавления.Вставить("ТолькоОдинФайл", Ложь);
	Возврат ПараметрыДобавления;
КонецФункции

// Добавить со сканера. Если работа со сканером не была предварительно настроена, 
// то будут вызвана форма настроек сканирования.
// 
// Параметры:
//  ПараметрыДобавления - см. ПараметрыДобавленияСоСканера
//  ПараметрыСканирования - см. ПараметрыСканирования
//
Процедура ДобавитьСоСканера(ПараметрыДобавления, ПараметрыСканирования = Неопределено) Экспорт
	
	РаботаСФайламиСлужебныйКлиент.ДобавитьСоСканера(ПараметрыДобавления, ПараметрыСканирования);
	
КонецПроцедуры

// Проверяет ограничения клиента для работы со сканером.
// 
// Возвращаемое значение:
//   см. РаботаСФайламиСлужебныйКлиент.ДоступноСканирование
//
Функция ДоступноСканирование() Экспорт
	Возврат РаботаСФайламиСлужебныйКлиент.ДоступноСканирование();
КонецФункции

// Проверяет ограничения клиента для работы со сканером, установлена ли компонента сканирования и 
// есть ли хоть один подключенный сканер.
// 
// Параметры:
//  ОповещениеРезультата - ОписаниеОповещения - процедура куда будет передан результат проверки:
//   * Результат - Булево - признак доступности сканирования.
//   * ДополнительныеПараметры - Произвольный - значение, указанное при создании описания оповещения.
//
Процедура ДоступнаКомандаСканировать(ОповещениеРезультата) Экспорт
	
	Если ДоступноСканирование() Тогда
		ОписаниеОповещения = Новый ОписаниеОповещения("ДоступнаКомандаСканироватьЗавершение", ЭтотОбъект, ОповещениеРезультата);
		РаботаСФайламиСлужебныйКлиент.ПроинициализироватьКомпоненту(ОписаниеОповещения);
	Иначе
		ВыполнитьОбработкуОповещения(ОповещениеРезультата, Ложь);
	КонецЕсли;
	
КонецПроцедуры

// Получает настройки сканирования пользователя.
// 
// Параметры:
//  ИдентификаторКлиента - УникальныйИдентификатор - идентификатор клиента
// 
// Возвращаемое значение:
//   см. РаботаСФайламиКлиентСервер.НастройкиСканированияПользователя
//
Функция ПолучитьНастройкиСканированияПользователя(ИдентификаторКлиента = Неопределено) Экспорт
	
	Если ИдентификаторКлиента = Неопределено Тогда
		ИдентификаторКлиента = РаботаСФайламиСлужебныйКлиент.ИдентификаторКлиента();
	КонецЕсли;
	
	Возврат РаботаСФайламиСлужебныйВызовСервера.ПолучитьНастройкиСканированияПользователя(ИдентификаторКлиента);
	
КонецФункции

// Сохраняет настройки сканирования пользователя.
// 
// Параметры:
//  НастройкиСканированияПользователя - см. РаботаСФайламиКлиентСервер.НастройкиСканированияПользователя
//  ИдентификаторКлиента - УникальныйИдентификатор - идентификатор клиента
//
Процедура СохранитьНастройкиСканированияПользователя(НастройкиСканированияПользователя, ИдентификаторКлиента = Неопределено) Экспорт
	
	Если ИдентификаторКлиента = Неопределено Тогда
		ИдентификаторКлиента = РаботаСФайламиСлужебныйКлиент.ИдентификаторКлиента();
	КонецЕсли;
	
	РаботаСФайламиСлужебныйВызовСервера.СохранитьНастройкиСканированияПользователя(НастройкиСканированияПользователя, ИдентификаторКлиента);
	
КонецПроцедуры

#Область УправлениеПрисоединеннымиФайлами

// Обработчик события ПриОткрытии управляемой формы владельца файла.
//
// Параметры:
//  Форма - ФормаКлиентскогоПриложения - форма владельца файла.
//  Отказ - Булево - стандартный параметр события ПриОткрытии управляемой формы.
//
Процедура ПриОткрытии(Форма, Отказ) Экспорт
	НаличиеСканера = РаботаСФайламиСлужебныйКлиент.ДоступноСканирование();
	Если Не НаличиеСканера Тогда
		ИзменитьВидимостьДополнительныхКоманд(Форма);
	КонецЕсли;
КонецПроцедуры

// Обработчик события ОбработкаОповещения управляемой формы владельца файла.
//
// Параметры:
//  Форма      - ФормаКлиентскогоПриложения - форма владельца файла.
//  ИмяСобытия - Строка - стандартный параметр события ОбработкаОповещения управляемой формы.
//
Процедура ОбработкаОповещения(Форма, ИмяСобытия) Экспорт
	
	Если ИмяСобытия <> "Запись_Файл" Тогда
		Возврат;
	КонецЕсли;
		
	Для НомерЭлемента = 0 По Форма.ПараметрыРаботыСФайлами.ОписанияЭлементовФормы.ВГраница() Цикл
		
		ОтображатьКоличество = Форма.ПараметрыРаботыСФайлами.ОписанияЭлементовФормы[НомерЭлемента].ОтображатьКоличество;
		Если Не ОтображатьКоличество Тогда
			Продолжить;
		КонецЕсли;
		
		ВладелецПрисоединенныхФайлов = ЗначениеПараметраПрисоединенногоФайла(Форма, НомерЭлемента, "ПутьКДаннымВладельца");
		КоличествоПрисоединенныхФайлов = РаботаСФайламиСлужебныйВызовСервера.КоличествоПрисоединенныхФайлов(ВладелецПрисоединенныхФайлов);
		КоличествоПрисоединенныхФайловСтрокой = Формат(КоличествоПрисоединенныхФайлов, "ЧГ=");
		
		Гиперссылка = Форма.Элементы.Найти(РаботаСФайламиКлиентСервер.ПрефиксКоманд() + РаботаСФайламиКлиентСервер.ИмяКомандыОткрытьСписок() + НомерЭлемента);
		Если Гиперссылка = Неопределено Тогда
			Продолжить;
		КонецЕсли;
			
		ПозицияКоличестваВЗаголовке = СтрНайти(Гиперссылка.Заголовок, "(");
		Если ПозицияКоличестваВЗаголовке = 0 Тогда
			Гиперссылка.Заголовок = Гиперссылка.Заголовок 
						+ ?(КоличествоПрисоединенныхФайлов = 0, "",
						" (" + КоличествоПрисоединенныхФайловСтрокой + ")");
		Иначе
			Гиперссылка.Заголовок = Лев(Гиперссылка.Заголовок, ПозицияКоличестваВЗаголовке - 1)
						+ ?(КоличествоПрисоединенныхФайлов = 0, "",
						"(" + КоличествоПрисоединенныхФайловСтрокой + ")");
		КонецЕсли;
		
	КонецЦикла;
	
КонецПроцедуры

// Обработчик выполнения дополнительных команд управления присоединенными файлами.
//
// Параметры:
//  Форма   - ФормаКлиентскогоПриложения - форма владельца файла.
//  Команда - КомандаФормы - выполняемая команда.
//
Процедура КомандаУправленияПрисоединеннымиФайлами(Форма, Команда) Экспорт
	
	Позиция = СтрНайти(Команда.Имя, "_",НаправлениеПоиска.СКонца);
	Если Позиция = 0 Тогда
		Возврат;
	КонецЕсли;
	
	НомерСтрокой = Сред(Команда.Имя, Позиция + 1);
	
	НомерЭлемента = Число(СтрЗаменить(НомерСтрокой, РаботаСФайламиКлиентСервер.ТолькоОдинФайлТекст(), ""));
	ВладелецПрисоединенныхФайлов = ЗначениеПараметраПрисоединенногоФайла(Форма, НомерЭлемента, "ПутьКДаннымВладельца");
	Если Не ЗначениеЗаполнено(ВладелецПрисоединенныхФайлов) Тогда
		
		ПараметрыОбработчика = Новый Структура;
		ПараметрыОбработчика.Вставить("Действие", "ВыполнениеКоманды");
		ПараметрыОбработчика.Вставить("Форма", Форма);
		ПараметрыОбработчика.Вставить("Команда", Команда);
		ПараметрыОбработчика.Вставить("НомерЭлемента", НомерЭлемента);
		
		ЗадатьВопросОЗаписиВладельца(ПараметрыОбработчика);
		
	Иначе
		КомандаУправленияПрисоединеннымиФайламиЗавершение(Форма, Команда, ВладелецПрисоединенныхФайлов);
	КонецЕсли;
	
КонецПроцедуры

// Обработчик нажатия на поле предпросмотра.
//
// Параметры:
//  Форма                - ФормаКлиентскогоПриложения - форма владельца файла.
//  Элемент              - ПолеФормы - поле предпросмотра.
//  СтандартнаяОбработка - Булево - стандартный параметр события Нажатие поля формы.
//  Просмотр             - Булево - если параметр принимает значение Истина, открывает файл
//                       для просмотра. Иначе - загружает файл с компьютера.
//                       Значение по умолчанию - Ложь.
//
Процедура ПолеПредпросмотраНажатие(Форма, Элемент, СтандартнаяОбработка, Просмотр = Ложь) Экспорт
	
	СтандартнаяОбработка = Ложь;
	Если Форма.ТолькоПросмотр Или Элемент.ТолькоПросмотр Тогда
		Возврат;
	КонецЕсли;
	
	НомерЭлемента = Число(СтрЗаменить(Элемент.Имя, "ПолеКартинкиПрисоединенногоФайла", ""));
	ТолькоОдинФайл = Форма.ПараметрыРаботыСФайлами.ОписанияЭлементовФормы[НомерЭлемента].ТолькоОдинФайл;
	ВладелецПрисоединенныхФайлов = ЗначениеПараметраПрисоединенногоФайла(Форма, Число(НомерЭлемента), "ПутьКДаннымВладельца");
	
	Если Не ЗначениеЗаполнено(ВладелецПрисоединенныхФайлов) Тогда
		
		ПараметрыОбработчика = Новый Структура;
		ПараметрыОбработчика.Вставить("Действие", "ПредпросмотрНажатие");
		ПараметрыОбработчика.Вставить("Форма", Форма);
		ПараметрыОбработчика.Вставить("Элемент", Элемент);
		ПараметрыОбработчика.Вставить("Просмотр", Просмотр);
		ПараметрыОбработчика.Вставить("НомерЭлемента", НомерЭлемента);
		ПараметрыОбработчика.Вставить("ТолькоОдинФайл", ТолькоОдинФайл);
		
		ЗадатьВопросОЗаписиВладельца(ПараметрыОбработчика);
		
	Иначе
		ПолеПредпросмотраНажатиеЗавершение(Форма, ВладелецПрисоединенныхФайлов, Элемент, СтандартнаяОбработка,
			Просмотр, ТолькоОдинФайл);
	КонецЕсли;
	
КонецПроцедуры

// Обработчик перетаскивания на поле предпросмотра.
//
// Параметры:
//  Форма                   - ФормаКлиентскогоПриложения - форма владельца файла.
//  Элемент                 - ПолеФормы - поле предпросмотра.
//  ПараметрыПеретаскивания - ПараметрыПеретаскивания - стандартный параметр события Перетаскивание 
//                          поля формы.
//  СтандартнаяОбработка    - Булево - стандартный параметр события Перетаскивание поля формы.
//
Процедура ПолеПредпросмотраПеретаскивание(Форма, Элемент, ПараметрыПеретаскивания, СтандартнаяОбработка) Экспорт
	
	СтандартнаяОбработка = Ложь;
	Если Форма.ТолькоПросмотр Или Элемент.ТолькоПросмотр Тогда
		Возврат;
	КонецЕсли;
	
	НомерЭлемента = Число(СтрЗаменить(Элемент.Имя, "ПолеКартинкиПрисоединенногоФайла", ""));
	ТолькоОдинФайл = Форма.ПараметрыРаботыСФайлами.ОписанияЭлементовФормы[НомерЭлемента].ТолькоОдинФайл;
	ВладелецПрисоединенныхФайлов = ЗначениеПараметраПрисоединенногоФайла(Форма, Число(НомерЭлемента), "ПутьКДаннымВладельца");
	
	ПараметрыОбработчика = Новый Структура;
	ПараметрыОбработчика.Вставить("Действие", "Перетаскивание");
	ПараметрыОбработчика.Вставить("Форма", Форма);
	ПараметрыОбработчика.Вставить("Элемент", Элемент);
	ПараметрыОбработчика.Вставить("НомерЭлемента", НомерЭлемента);
	ПараметрыОбработчика.Вставить("ТолькоОдинФайл", ТолькоОдинФайл);
	ПараметрыОбработчика.Вставить("ПараметрыПеретаскивания", ПараметрыПеретаскивания);
	ПараметрыОбработчика.Вставить("ВладелецПрисоединенныхФайлов", ВладелецПрисоединенныхФайлов);
	
	Если Не ЗначениеЗаполнено(ВладелецПрисоединенныхФайлов) Тогда
		ЗадатьВопросОЗаписиВладельца(ПараметрыОбработчика);
	Иначе
		ОповещениеОбУстановке = Новый ОписаниеОповещения("ПолеПредпросмотраПеретаскиваниеЗавершение", ЭтотОбъект, ПараметрыОбработчика);
		ФайловаяСистемаКлиент.ПодключитьРасширениеДляРаботыСФайлами(ОповещениеОбУстановке, , Ложь);
	КонецЕсли;
	
КонецПроцедуры

// Обработчик проверки перетаскивания на поле предпросмотра.
//
// Параметры:
//  Форма                   - ФормаКлиентскогоПриложения - форма владельца файла.
//  Элемент                 - ПолеФормы - поле предпросмотра.
//  ПараметрыПеретаскивания - ПараметрыПеретаскивания - стандартный параметр события Проверка
//                          перетаскивания поля формы.
//  СтандартнаяОбработка    - Булево - стандартный параметр события Проверка перетаскивания поля формы.
//
Процедура ПолеПредпросмотраПроверкаПеретаскивания(Форма, Элемент, ПараметрыПеретаскивания, СтандартнаяОбработка) Экспорт
	
	СтандартнаяОбработка = Ложь;
	
КонецПроцедуры

#КонецОбласти

#Область УстаревшиеПроцедурыИФункции

// Устарела. Следует использовать РаботаСФайламиКлиент.ОткрытьФормуФайла
// Открывает форму файла из формы элемента справочника файлов. Форма элемента закрывается.
// 
// Параметры:
//  Форма     - ФормаКлиентскогоПриложения - форма справочника присоединенных файлов.
//
Процедура ПерейтиКФормеФайла(Знач Форма) Экспорт
	
	ПрисоединенныйФайл = Форма.Ключ;
	
	Форма.Закрыть();
	
	Для Каждого ОкноПриложения Из ПолучитьОкна() Цикл
		
		Содержимое = ОкноПриложения.ПолучитьСодержимое();
		
		Если Содержимое = Неопределено Тогда
			Продолжить;
		КонецЕсли;
		
		Если Содержимое.ИмяФормы = "Обработка.РаботаСФайлами.Форма.ПрисоединенныйФайл" Тогда
			Если Содержимое.Параметры.Свойство("ПрисоединенныйФайл")
				И Содержимое.Параметры.ПрисоединенныйФайл = ПрисоединенныйФайл Тогда
				ОкноПриложения.Активизировать();
				Возврат;
			КонецЕсли;
		КонецЕсли;
		
	КонецЦикла;
	
	ОткрытьФормуФайла(ПрисоединенныйФайл);
	
КонецПроцедуры

#КонецОбласти

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

// Процедура предназначена для печати файла соответствующим приложением
//
// Параметры:
//  ДанныеФайла          - см. РаботаСФайлами.ДанныеФайла.
//  ИмяОткрываемогоФайла - Строка.
//
Процедура НапечататьФайлПриложением(ДанныеФайла, ИмяОткрываемогоФайла)
	
#Если МобильныйКлиент Тогда
	ПоказатьПредупреждение(, НСтр("ru = 'Печать файлов данного типа возможна только из приложения для Windows или Linux.'"));
	Возврат;
#Иначе
	РасширенияИсключения = 
		" m3u, m4a, mid, midi, mp2, mp3, mpa, rmi, wav, wma, 
		| 3g2, 3gp, 3gp2, 3gpp, asf, asx, avi, m1v, m2t, m2ts, m2v, m4v, mkv, mov, mp2v, mp4, mp4v, mpe, mpeg, mts, vob, wm, wmv, wmx, wvx,
		| 7z, zip, rar, arc, arh, arj, ark, p7m, pak, package, 
		| app, com, exe, jar, dll, res, iso, isz, mdf, mds,
		| cf, dt, epf, erf";
	
	Расширение = НРег(ДанныеФайла.Расширение);
	
	Если СтрНайти(РасширенияИсключения, " " + Расширение + ",") > 0 Тогда
		ПоказатьПредупреждение(, НСтр("ru = 'Печать файлов данного типа недоступна.'"));
		Возврат;
	ИначеЕсли Расширение = "grs" Тогда
		Схема = Новый ГрафическаяСхема;
		Схема.Прочитать(ИмяОткрываемогоФайла);
		Схема.Напечатать();
		Возврат;
	КонецЕсли;
	
	Попытка
		
		Если ОбщегоНазначенияКлиент.ЭтоWindowsКлиент() Тогда
			ИмяОткрываемогоФайла = СтрЗаменить(ИмяОткрываемогоФайла, "/", "\");
		КонецЕсли;
		
		НапечататьИзПриложенияПоИмениФайла(ИмяОткрываемогоФайла);
		
	Исключение
		ПоказатьПредупреждение(, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не удалось распечатать файл по причине:
				|%1'"), ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()))); 
		
	КонецПопытки;
#КонецЕсли

КонецПроцедуры

// Процедура печати Файла
//
// Параметры:
//  ОбработчикРезультата - ОписаниеОповещения
//  ПараметрыВыполнения  - Структура:
//        * НомерФайла               - Число - номер текущего файла.
//        * ДанныеФайла              - Структура
//        * УникальныйИдентификатор  - УникальныйИдентификатор.
//
Процедура НапечататьФайлыВыполнение(ОбработчикРезультата, ПараметрыВыполнения) Экспорт
	
	ОбработкаПрерыванияПользователя();
	
	Если ПараметрыВыполнения.НомерФайла >= ПараметрыВыполнения.ДанныеФайлов.Количество() Тогда
		Возврат;
	КонецЕсли;
	ПараметрыВыполнения.ДанныеФайла = 
		РаботаСФайламиСлужебныйВызовСервера.ДанныеФайлаДляПечати(ПараметрыВыполнения.ДанныеФайлов[ПараметрыВыполнения.НомерФайла],
		ПараметрыВыполнения.УникальныйИдентификатор);
		
#Если ВебКлиент Тогда
	Если ПараметрыВыполнения.ДанныеФайла.Расширение <> "mxl" Тогда
		Текст = НСтр("ru = 'Сохраните файл на компьютер, после чего распечатайте его при помощи приложения, предназначенного для работы с данным файлом.'");
		ПоказатьПредупреждение(, Текст);
		Возврат;
	КонецЕсли;
#КонецЕсли
	
	Если ПараметрыВыполнения.ДанныеФайла.Свойство("ТабличныйДокумент") Тогда
		ПараметрыВыполнения.ДанныеФайла.ТабличныйДокумент.Напечатать();
		// переходим к печати следующего файла.
		ПараметрыВыполнения.НомерФайла = ПараметрыВыполнения.НомерФайла + 1;
		Обработчик = Новый ОписаниеОповещения("НапечататьФайлыВыполнение", ЭтотОбъект, ПараметрыВыполнения);
		ВыполнитьОбработкуОповещения(Обработчик);
		Возврат
	КонецЕсли;
	
	Если РаботаСФайламиСлужебныйКлиент.РасширениеРаботыСФайламиПодключено() Тогда
		Обработчик = Новый ОписаниеОповещения("НапечататьФайлПослеПолученияВерсииВРабочийКаталог", ЭтотОбъект, ПараметрыВыполнения);
		РаботаСФайламиСлужебныйКлиент.ПолучитьФайлВерсииВРабочийКаталог(
			Обработчик,
			ПараметрыВыполнения.ДанныеФайла,
			"",
			ПараметрыВыполнения.УникальныйИдентификатор);
	Иначе
		ПараметрыВыполнения.ДанныеФайла = РаботаСФайламиСлужебныйВызовСервера.ДанныеФайлаДляОткрытия(ПараметрыВыполнения.ДанныеФайлов[ПараметрыВыполнения.НомерФайла], Неопределено);
		ОткрытьФайл(ПараметрыВыполнения.ДанныеФайла, Ложь);
	КонецЕсли;
КонецПроцедуры

// Процедура печати Файла после получения на компьютер.
//
// Параметры:
//  Результат - Структура:
//    * ФайлПолучен - Булево
//    * ПолноеИмяФайла - Строка
//  ПараметрыВыполнения  - Структура:
//    * НомерФайла               - Число - номер текущего файла.
//    * ДанныеФайла              - Структура
//    * УникальныйИдентификатор  - УникальныйИдентификатор.
//
Процедура НапечататьФайлПослеПолученияВерсииВРабочийКаталог(Результат, ПараметрыВыполнения) Экспорт

	Если Результат.ФайлПолучен Тогда
		
		Если ПараметрыВыполнения.НомерФайла >= ПараметрыВыполнения.ДанныеФайлов.Количество() Тогда
			Возврат;
		КонецЕсли;
	
		НапечататьФайлПриложением(ПараметрыВыполнения.ДанныеФайла, Результат.ПолноеИмяФайла);
		
	КонецЕсли;

	// переходим к печати следующего файла.
	ПараметрыВыполнения.НомерФайла = ПараметрыВыполнения.НомерФайла + 1;
	Обработчик = Новый ОписаниеОповещения("НапечататьФайлыВыполнение", ЭтотОбъект, ПараметрыВыполнения);
	ВыполнитьОбработкуОповещения(Обработчик);
	
КонецПроцедуры

// Выполняет печать файла внешним приложением.
//
// Параметры:
//  ИмяОткрываемогоФайла - Строка
//
Процедура НапечататьИзПриложенияПоИмениФайла(ИмяОткрываемогоФайла)
	
	ФайловаяСистемаКлиент.НапечататьИзПриложенияПоИмениФайла(ИмяОткрываемогоФайла);

КонецПроцедуры

Процедура ОткрытьФормуНастройкиСканированияЗавершение(РезультатПроверкиИнициализации, ПараметрыВыполнения) Экспорт
	
	КомпонентаУстановлена = РезультатПроверкиИнициализации.Подключено;
	
	Если Не КомпонентаУстановлена Тогда
		Если ЗначениеЗаполнено(РезультатПроверкиИнициализации.ОписаниеОшибки) Тогда
			ПоказатьПредупреждение(, РезультатПроверкиИнициализации.ОписаниеОшибки);
		КонецЕсли;
		Возврат;
	КонецЕсли;
	
	РаботаСФайламиСлужебныйКлиент.ВключитьЛогированиеКомпоненты(РезультатПроверкиИнициализации.ПодключаемыйМодуль);
	ИдентификаторКлиента = РаботаСФайламиСлужебныйКлиент.ИдентификаторКлиента();
	
	ПараметрыФормы = Новый Структура;
	ПараметрыФормы.Вставить("КомпонентаУстановлена", КомпонентаУстановлена);
	ПараметрыФормы.Вставить("ИдентификаторКлиента",  ИдентификаторКлиента);
	
	ОткрытьФорму("Обработка.Сканирование.Форма.НастройкаСканирования", ПараметрыФормы);
	
КонецПроцедуры

Процедура ВопросОНеобходимостиЗаписиПослеЗавершения(Результат, ДополнительныеПараметры) Экспорт
	
	Если Результат = КодВозвратаДиалога.ОК Тогда
		Возврат;
	КонецЕсли;
	
КонецПроцедуры

Функция ИзображенияДляОбъединения(ОбъектыДляОбъединения, ИспользоватьImageMagick = Ложь)
	
	ИзображенияДляОбъединения = Новый Массив;
	
	Если ИспользоватьImageMagick Тогда
		Для Каждого ОбъектДляОбъединения Из ОбъектыДляОбъединения Цикл
			ИмяФайла = Неопределено;
			#Если Не ВебКлиент И Не МобильныйКлиент Тогда
				// АПК:441-выкл файл является результатом метода
				ИмяВременногоФайла = ПолучитьИмяВременногоФайла();
				// АПК:441-вкл
			#Иначе
				ИмяВременногоФайла = Неопределено;			
			#КонецЕсли
			
			Если ОбъектДляОбъединения = Неопределено Тогда
				Продолжить;
			ИначеЕсли ТипЗнч(ОбъектДляОбъединения) = Тип("ДвоичныеДанные") Тогда
				ИмяФайла = ИмяВременногоФайла;
				ОбъектДляОбъединения.Записать(ИмяФайла);
			ИначеЕсли ТипЗнч(ОбъектДляОбъединения) = Тип("Строка") Тогда
				Если ЭтоАдресВременногоХранилища(ОбъектДляОбъединения) Тогда
					СодержимоеАдреса = ПолучитьИзВременногоХранилища(ОбъектДляОбъединения);
					Если ТипЗнч(СодержимоеАдреса) = Тип("ДвоичныеДанные") Тогда
						ИмяФайла = ИмяВременногоФайла;
						СодержимоеАдреса.Записать(ИмяФайла);
					ИначеЕсли ТипЗнч(СодержимоеАдреса) = Тип("Картинка") Тогда
						ДанныеКартинки = СодержимоеАдреса.ПолучитьДвоичныеДанные();
						ИмяФайла = ИмяВременногоФайла;
						ДанныеКартинки.Записать(ИмяФайла);
					КонецЕсли;
				Иначе
					ИмяФайла = ОбъектДляОбъединения;
				КонецЕсли;
			ИначеЕсли РаботаСФайламиСлужебныйВызовСервера.ЭтоЭлементРаботаСФайлами(ОбъектДляОбъединения) Тогда
				ДанныеФайла = РаботаСФайламиСлужебныйВызовСервера.ДанныеФайла(ОбъектДляОбъединения);
				СодержимоеАдреса = ПолучитьИзВременногоХранилища(ДанныеФайла.СсылкаНаДвоичныеДанныеФайла);
				ИмяФайла = ИмяВременногоФайла;
				СодержимоеАдреса.Записать(ИмяФайла);
			КонецЕсли;
			
			Если ИмяФайла <> Неопределено Тогда
				ИзображенияДляОбъединения.Добавить(ИмяФайла);
			КонецЕсли;
			
		КонецЦикла;
	Иначе
		Для Каждого ОбъектДляОбъединения Из ОбъектыДляОбъединения Цикл
			Изображение = Неопределено;
			Если ОбъектДляОбъединения = Неопределено Тогда
				Продолжить;
			ИначеЕсли ТипЗнч(ОбъектДляОбъединения) = Тип("ДвоичныеДанные") Тогда
				Изображение = Новый Картинка(ОбъектДляОбъединения);
			ИначеЕсли ТипЗнч(ОбъектДляОбъединения) = Тип("Строка") Тогда
				Если ЭтоАдресВременногоХранилища(ОбъектДляОбъединения) Тогда
					СодержимоеАдреса = ПолучитьИзВременногоХранилища(ОбъектДляОбъединения);
					Если ТипЗнч(СодержимоеАдреса) = Тип("ДвоичныеДанные") Тогда
						Изображение = Новый Картинка(СодержимоеАдреса);
					ИначеЕсли ТипЗнч(СодержимоеАдреса) = Тип("Картинка") Тогда
						Изображение = СодержимоеАдреса;
					КонецЕсли;
				Иначе
					Изображение = Новый Картинка(ОбъектДляОбъединения);
				КонецЕсли;
			ИначеЕсли РаботаСФайламиСлужебныйВызовСервера.ЭтоЭлементРаботаСФайлами(ОбъектДляОбъединения) Тогда
				ДанныеФайла = РаботаСФайламиСлужебныйВызовСервера.ДанныеФайла(ОбъектДляОбъединения);
				СодержимоеАдреса = ПолучитьИзВременногоХранилища(ДанныеФайла.СсылкаНаДвоичныеДанныеФайла);
				Изображение = Новый Картинка(СодержимоеАдреса);
			КонецЕсли;
			
			Если Изображение <> Неопределено Тогда
				ИзображенияДляОбъединения.Добавить(Изображение);
			КонецЕсли;
			
		КонецЦикла;
	КонецЕсли;
	
	Возврат ИзображенияДляОбъединения;
КонецФункции

Функция РезультатОбъединенияВМногостраничныйДокумент()
	Результат = Новый Структура;
	Результат.Вставить("ИмяФайлаРезультата", "");
	Результат.Вставить("ДвоичныеДанные");
	Результат.Вставить("ОписаниеОшибки", "");
	Результат.Вставить("Успешно", Ложь);	
	Возврат Результат;
КонецФункции

Процедура ОбъединитьВМногостраничныйФайлПослеВыполненияКоманды(РезультатImageMagick, Контекст) Экспорт

	ФайлыИзображений = Контекст.ФайлыИзображений;
	ТипРезультата = Контекст.ТипРезультата;
	ИмяФайлаРезультата = Контекст.ИмяФайлаРезультата;
	ОповещениеВозврата = Контекст.ОповещениеВозврата;
	
	Результат = РезультатОбъединенияВМногостраничныйДокумент();

	Если РезультатImageMagick.КодВозврата <> 0 Тогда
		Результат.ОписаниеОшибки = РезультатImageMagick.ОписаниеОшибки;
		ВыполнитьОбработкуОповещения(ОповещениеВозврата, Результат);
		Возврат;
	КонецЕсли;
	
	Для Каждого ФайлИзображения Из ФайлыИзображений Цикл
		УдалитьФайлы(ФайлИзображения);
	КонецЦикла;
	
	Если ТипРезультата = ТипРезультатаКонвертацииИмяФайла() Тогда
		Результат.ИмяФайлаРезультата = ИмяФайлаРезультата;
	ИначеЕсли ТипРезультата = ТипРезультатаКонвертацииДвоичныеДанные() Тогда
		ДанныеPDF = Новый ДвоичныеДанные(ИмяФайлаРезультата);
		УдалитьФайлы(ИмяФайлаРезультата);
		Результат.ДвоичныеДанные =  ДанныеPDF;
	КонецЕсли;
	Результат.Успешно = Истина;
	
	ВыполнитьОбработкуОповещения(ОповещениеВозврата, Результат);
		
КонецПроцедуры

Процедура ДоступнаКомандаСканироватьЗавершение(РезультатПроверкиИнициализации, ОповещениеРезультата) Экспорт
	ДоступнаКомандаСканировать = РезультатПроверкиИнициализации.Подключено;
	ПодключаемыйМодуль = РезультатПроверкиИнициализации.ПодключаемыйМодуль;
	
	Если ДоступнаКомандаСканировать Тогда
		РаботаСФайламиСлужебныйКлиент.ВключитьЛогированиеКомпоненты(РезультатПроверкиИнициализации.ПодключаемыйМодуль);
	КонецЕсли;
	
	ДоступнаКомандаСканировать = ДоступнаКомандаСканировать 
		И РаботаСФайламиСлужебныйКлиент.ЕстьУстройства(Неопределено, ПодключаемыйМодуль, Ложь);

	ВыполнитьОбработкуОповещения(ОповещениеРезультата, ДоступнаКомандаСканировать);	
КонецПроцедуры

Процедура ПослеПроверкиНаличияПрограммыКонвертации(РезультатЗапуска, Контекст) Экспорт
	Если СтрНайти(РезультатЗапуска.ПотокВывода, "ImageMagick") = 0  Тогда
		НастройкиСканированияПользователя = Контекст.НастройкиСканированияПользователя;
		ПутьКПрограммеКонвертации = НастройкиСканированияПользователя.ПутьКПрограммеКонвертации;
		ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru='Ошибочно указан путь к программе %1.
		|Объединение многостраничных документов выполняется штатными средствами.
		|Указан путь: %2'"), "ImageMagick", ПутьКПрограммеКонвертации); 
		ЖурналРегистрацииКлиент.ДобавитьСообщениеДляЖурналаРегистрации(СобытиеЖурналаРегистрации(),
			"Предупреждение", ТекстОшибки,, Истина);
		Контекст.ПараметрыКонвертацииГрафическогоДокумента.ИспользоватьImageMagick = Ложь;
	КонецЕсли;
	ОбъединитьВМногостраничныйФайлПродолжение(Контекст);
КонецПроцедуры
	
Процедура ОбъединитьВМногостраничныйФайлПродолжение(Контекст)
	ОповещениеВозврата = Контекст.ОповещениеВозврата;
	ОбъектыДляОбъединения = Контекст.ОбъектыДляОбъединения;
	ПараметрыКонвертацииГрафическогоДокумента = Контекст.ПараметрыКонвертацииГрафическогоДокумента;
	НастройкиСканированияПользователя = Контекст.НастройкиСканированияПользователя;
	
	ИспользоватьImageMagick = ПараметрыКонвертацииГрафическогоДокумента.ИспользоватьImageMagick; 
	ПутьКПрограммеКонвертации = НастройкиСканированияПользователя.ПутьКПрограммеКонвертации;
	
	Результат = РезультатОбъединенияВМногостраничныйДокумент();
	
	#Если Не ВебКлиент И Не МобильныйКлиент Тогда
	ИмяФайлаРезультата = ПараметрыКонвертацииГрафическогоДокумента.ИмяФайлаРезультата;
	
	Если Не ЗначениеЗаполнено(ИмяФайлаРезультата) Тогда
		// АПК:441-выкл файл не удаляется, если является результатом метода
		ИмяФайлаРезультата = ПолучитьИмяВременногоФайла(ПараметрыКонвертацииГрафическогоДокумента.ФорматРезультата);
		// АПК:441-вкл
	КонецЕсли;
	
	Если Не ИспользоватьImageMagick Тогда
		ИзображенияДляОбъединения = ИзображенияДляОбъединения(ОбъектыДляОбъединения);
		Если ПараметрыКонвертацииГрафическогоДокумента.ФорматРезультата = "pdf" Тогда
			ТабличныйДокумент = РаботаСФайламиСлужебныйВызовСервера.НовыйТабличныйДокументНаСервере(ИзображенияДляОбъединения.Количество());
			Поток = Новый ПотокВПамяти();
			ТабличныйДокумент.Записать(Поток, ТипФайлаТабличногоДокумента.PDF);
			
			ДокументPDF = Новый ДокументPDF();
			ДокументPDF.Прочитать(Поток);
			Для ИндексОбъекта = 0 По ИзображенияДляОбъединения.ВГраница() Цикл
				Описание = Новый ОписаниеОтображаемогоОбъектаPDF;
				Описание.Имя           = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru='Изображение № %1'"), ИндексОбъекта);
				Изображение = ИзображенияДляОбъединения[ИндексОбъекта];
				Ширина = Изображение.Ширина();
				Высота = Изображение.Высота();
				ОтношениеА4 = 210/297;
				
				Если ОтношениеА4*Высота > Ширина Тогда
					Описание.Высота        = 269; //297
					Описание.Ширина        = Описание.Высота * Ширина/Высота; //210
				Иначе
					Описание.Ширина        = 190; //210
					Описание.Высота        = Описание.Ширина * Высота/Ширина; //297 
				КонецЕсли;
				Описание.Лево          = 0;
				Описание.Верх          = 0;
				Описание.НомерСтраницы = ИндексОбъекта+1;
				Описание.Объект        = Изображение;
				ДокументPDF.ДобавитьОтображаемыйОбъект(Описание);
			КонецЦикла;
			ДокументPDF.Записать(Поток);
			ДанныеРезультата = Поток.ЗакрытьИПолучитьДвоичныеДанные();
		ИначеЕсли ПараметрыКонвертацииГрафическогоДокумента.ФорматРезультата = "tif" Тогда
			ИзображениеTif = РаботаСФайламиСлужебныйВызовСервера.ОбъединитьИзображенияВTifФайл(ИзображенияДляОбъединения);
			ДанныеРезультата = ИзображениеTif.ПолучитьДвоичныеДанные();
		КонецЕсли;
		
		Если ПараметрыКонвертацииГрафическогоДокумента.ТипРезультата = ТипРезультатаКонвертацииИмяФайла() Тогда
			ДанныеРезультата.Записать(ИмяФайлаРезультата);
			Результат.ИмяФайлаРезультата = ИмяФайлаРезультата;
			Результат.Успешно = Истина;
		ИначеЕсли ПараметрыКонвертацииГрафическогоДокумента.ТипРезультата = ТипРезультатаКонвертацииДвоичныеДанные() Тогда
			Результат.ДвоичныеДанные = ДанныеРезультата;
			Результат.Успешно = Истина;
		КонецЕсли;
		
		ВыполнитьОбработкуОповещения(ОповещениеВозврата, Результат);
	Иначе
		ФайлыИзображений = ИзображенияДляОбъединения(ОбъектыДляОбъединения, Истина);
		
		СтрокаФайловИзображений = """" + СтрСоединить(ФайлыИзображений, """" + " " + """") + """";
		КомандыСистемы = """" + ПутьКПрограммеКонвертации + """" +" "+ СтрокаФайловИзображений + " " +""""+ ИмяФайлаРезультата+"""";
		
		Контекст = Новый Структура;
		Контекст.Вставить("ФайлыИзображений", ФайлыИзображений);
		Контекст.Вставить("ТипРезультата", ПараметрыКонвертацииГрафическогоДокумента.ТипРезультата);
		Контекст.Вставить("ИмяФайлаРезультата", ИмяФайлаРезультата);
		Контекст.Вставить("ОповещениеВозврата", ОповещениеВозврата);
		
		ПараметрыЗапускаПрограммы = ФайловаяСистемаКлиент.ПараметрыЗапускаПрограммы();
		ПараметрыЗапускаПрограммы.ДождатьсяЗавершения = Истина;
		ПараметрыЗапускаПрограммы.Оповещение = Новый ОписаниеОповещения("ОбъединитьВМногостраничныйФайлПослеВыполненияКоманды", 
			ЭтотОбъект, Контекст);
		ФайловаяСистемаКлиент.ЗапуститьПрограмму(КомандыСистемы, ПараметрыЗапускаПрограммы);
				
	КонецЕсли;
	
	#КонецЕсли
КонецПроцедуры

#Область УправлениеПрисоединеннымиФайлами

Функция ПараметрыКомандыУправления(Форма)
	
	ПараметрыВыполнения = Новый Структура;
	ПараметрыВыполнения.Вставить("Форма",              Форма);
	ПараметрыВыполнения.Вставить("Действие",           "ЗагрузитьФайл");
	ПараметрыВыполнения.Вставить("НомерЭлемента",      "");
	ПараметрыВыполнения.Вставить("ИдентификаторФормы", Форма.УникальныйИдентификатор);
	Возврат ПараметрыВыполнения;
	
КонецФункции

Функция ЗначениеПараметраПрисоединенногоФайла(Форма, Знач НомерЭлемента, ИмяПараметра)
	
	Если ТипЗнч(НомерЭлемента) = Тип("Строка") Тогда
		НомерЭлемента = Число(НомерЭлемента);
	КонецЕсли;
	
	ПутьКДанным = Форма.ПараметрыРаботыСФайлами.ОписанияЭлементовФормы[НомерЭлемента][ИмяПараметра];
	ЧастиПутиКДанным = СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок(ПутьКДанным, ".", Истина, Истина);
	Если ЧастиПутиКДанным.Количество() > 0 Тогда
		
		ЗначениеПараметра = Форма[ЧастиПутиКДанным[0]];
		Для Индекс = 1 По ЧастиПутиКДанным.ВГраница() Цикл
			ЗначениеПараметра = ЗначениеПараметра[ЧастиПутиКДанным[Индекс]];
		КонецЦикла;
		
		Возврат ЗначениеПараметра;
		
	КонецЕсли;
	
	Возврат Неопределено;
	
КонецФункции

Процедура ЗадатьВопросОЗаписиВладельца(ПараметрыОбработчикаЗавершения)
	
	ТекстВопроса = НСтр("ru = 'Данные еще не записаны.
		|Переход к присоединенным файлам возможен только после записи данных.
		|Данные будут записаны.'");
	ОбработчикОповещения = Новый ОписаниеОповещения("ПоказатьВопросЗаписиНовогоВладельца", ЭтотОбъект, ПараметрыОбработчикаЗавершения);
	
	ПоказатьВопрос(ОбработчикОповещения, ТекстВопроса, РежимДиалогаВопрос.ОКОтмена);
	
КонецПроцедуры

// Параметры:
//   Ответ - КодВозвратаДиалога
//         - Неопределено
//   ДополнительныеПараметры - Структура
//
Процедура ПоказатьВопросЗаписиНовогоВладельца(Ответ, ДополнительныеПараметры) Экспорт
	
	Если Ответ = КодВозвратаДиалога.ОК Тогда
		
		Форма = ДополнительныеПараметры.Форма; // РасширениеУправляемойФормыДляСправочника
		Если Не Форма.Записать() Тогда
			Возврат;
		КонецЕсли;
		
		СтандартнаяОбработка = Ложь;
		ВладелецПрисоединенныхФайлов = ЗначениеПараметраПрисоединенногоФайла(Форма, 
			ДополнительныеПараметры.НомерЭлемента, "ПутьКДаннымВладельца");
		
		Если Не ЗначениеЗаполнено(ВладелецПрисоединенныхФайлов) Тогда
			Возврат;
		КонецЕсли;
		
		Если ДополнительныеПараметры.Действие = "ВыполнениеКоманды" Тогда
			КомандаУправленияПрисоединеннымиФайламиЗавершение(Форма, ДополнительныеПараметры.Команда, ВладелецПрисоединенныхФайлов);
		ИначеЕсли ДополнительныеПараметры.Действие = "ПредпросмотрНажатие" Тогда
			ПолеПредпросмотраНажатиеЗавершение(Форма, ВладелецПрисоединенныхФайлов,
				ДополнительныеПараметры.Элемент, СтандартнаяОбработка,
				ДополнительныеПараметры.Просмотр, ДополнительныеПараметры.ТолькоОдинФайл);
		ИначеЕсли ДополнительныеПараметры.Действие = "Перетаскивание" Тогда
			ОповещениеОбУстановке = Новый ОписаниеОповещения("ПолеПредпросмотраПеретаскиваниеЗавершение", ЭтотОбъект, ДополнительныеПараметры);
			ФайловаяСистемаКлиент.ПодключитьРасширениеДляРаботыСФайлами(ОповещениеОбУстановке, , Ложь);
		КонецЕсли;
		
	КонецЕсли;
	
КонецПроцедуры

Процедура КомандаУправленияПрисоединеннымиФайламиЗавершение(Форма, Команда, ВладелецПрисоединенныхФайлов)
	
	ИмяКоманды = СтрЗаменить(Команда.Имя, РаботаСФайламиКлиентСервер.ПрефиксКоманд(), "");
	НомерЭлемента = "";

	Позиция = СтрНайти(ИмяКоманды, "_", НаправлениеПоиска.СКонца);
	Если Позиция > 0 Тогда 
		НомерЭлемента = СтрЗаменить(Сред(ИмяКоманды, Позиция + 1), РаботаСФайламиКлиентСервер.ТолькоОдинФайлТекст(), "");
		ИмяКоманды    = Лев(ИмяКоманды, Позиция - 1);
	КонецЕсли;
	
	ПараметрыВыполнения = ПараметрыКомандыУправления(Форма);
	ПараметрыВыполнения.НомерЭлемента = НомерЭлемента;
	
	ОбработчикЗавершения = Новый ОписаниеОповещения("ЗавершениеВыполненияКомандыСОповещением",
		ЭтотОбъект, ПараметрыВыполнения);
		
	ТипЧисло = Новый ОписаниеТипов("Число");
	НомерЭлемента = ТипЧисло.ПривестиЗначение(ПараметрыВыполнения.НомерЭлемента);
	ПараметрыДобавленияФайла = Новый Структура;
	ПараметрыДобавленияФайла.Вставить("МаксимальныйРазмер",
		Форма.ПараметрыРаботыСФайлами.ОписанияЭлементовФормы[НомерЭлемента].МаксимальныйРазмер);
	ПараметрыДобавленияФайла.Вставить("ФильтрДиалогаВыбора",
		Форма.ПараметрыРаботыСФайлами.ОписанияЭлементовФормы[НомерЭлемента].ФильтрДиалогаВыбора);
	ПараметрыДобавленияФайла.Вставить("НеОткрыватьКарточку", Истина);
	
	ИспользоватьДОДляХраненияФайловОбъекта = Ложь;

	// ИнтеграцияС1СДокументооборотом
	Если ОбщегоНазначенияКлиент.ПодсистемаСуществует("ИнтеграцияС1СДокументооборотом") Тогда
		ВерсияБИД = "1.0.0.0";
		СтандартныеПодсистемыКлиент.ПараметрыРаботыКлиента().Свойство("ВерсияБИД", ВерсияБИД);
		Если ОбщегоНазначенияКлиентСервер.СравнитьВерсии(ВерсияБИД, "3.0.2.4") >= 0 Тогда
			МодульИнтеграцияС1СДокументооборотБазоваяФункциональностьКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль(
				"ИнтеграцияС1СДокументооборотБазоваяФункциональностьКлиент");
			ИспользоватьДОДляХраненияФайловОбъекта =
				МодульИнтеграцияС1СДокументооборотБазоваяФункциональностьКлиент.ИспользоватьДОДляХраненияФайловОбъекта(
					Форма,
					Команда,
					ВладелецПрисоединенныхФайлов);
		КонецЕсли;
	КонецЕсли;
	// Конец ИнтеграцияС1СДокументооборотом
	
	Если СтрНачинаетсяС(ИмяКоманды, "ОткрытьСписок") Тогда
		
		Если ИспользоватьДОДляХраненияФайловОбъекта Тогда
			
			// ИнтеграцияС1СДокументооборотом
			МодульИнтеграцияС1СДокументооборотБазоваяФункциональностьКлиент.ОткрытьПрисоединенныеФайлы(
				ВладелецПрисоединенныхФайлов);
			// Конец ИнтеграцияС1СДокументооборотом
			
		Иначе
			
			ПараметрыФормы = Новый Структура();
			ПараметрыФормы.Вставить("ВладелецФайла", ВладелецПрисоединенныхФайлов);
			ПараметрыФормы.Вставить("СкрыватьВладельца", Истина);
			ПараметрыФормы.Вставить("ТекущаяСтрока", Форма.УникальныйИдентификатор);
			ОткрытьФорму("Обработка.РаботаСФайлами.Форма.ПрисоединенныеФайлы", ПараметрыФормы);
			
		КонецЕсли;
		
	ИначеЕсли СтрНачинаетсяС(ИмяКоманды, РаботаСФайламиКлиентСервер.ИмяКомандыЗагрузитьФайл()) Тогда
		
		Если ИспользоватьДОДляХраненияФайловОбъекта Тогда
			
			// ИнтеграцияС1СДокументооборотом
			МодульИнтеграцияС1СДокументооборотБазоваяФункциональностьКлиент.ДобавитьФайлСДискаКОбъектуИС(
				ВладелецПрисоединенныхФайлов,
				Форма.УникальныйИдентификатор);
			// Конец ИнтеграцияС1СДокументооборотом
			
		Иначе
			
			ИмяКоманды = СтрЗаменить(ИмяКоманды, РаботаСФайламиКлиентСервер.ИмяКомандыЗагрузитьФайл(), "");
			ФайлыВладельца = РаботаСФайламиСлужебныйВызовСервера.КоличествоПрисоединенныхФайлов(ВладелецПрисоединенныхФайлов, Истина);
			Если СтрНачинаетсяС(ИмяКоманды, "ТолькоОдинФайл")
				И ФайлыВладельца.Количество > 0 Тогда
				
				ДанныеФайла = ФайлыВладельца.ДанныеФайла; // См. РаботаСФайлами.ДанныеФайла
				
				ПараметрыВыполнения.Действие = "ЗаменитьФайл";
				ПараметрыВыполнения.Вставить("ФайлКартинки", ДанныеФайла.Ссылка);
				
				РаботаСФайламиСлужебныйКлиент.ОбновитьИзФайлаНаДискеСОповещением(ОбработчикЗавершения,
					ДанныеФайла, Форма.УникальныйИдентификатор, ПараметрыДобавленияФайла);
				
			Иначе
				ДобавитьФайл(ОбработчикЗавершения, ВладелецПрисоединенныхФайлов, Форма, 2, ПараметрыДобавленияФайла);
			КонецЕсли;
			
		КонецЕсли;
		
	ИначеЕсли СтрНачинаетсяС(ИмяКоманды, "ЗаголовокПрисоединенногоФайла") Тогда
		
		Размещение = ЗначениеПараметраПрисоединенногоФайла(Форма, ПараметрыВыполнения.НомерЭлемента, "ПутьКРеквизитуРазмещения");
		Если Не ЗначениеЗаполнено(Размещение) Тогда
			ДобавитьФайл(ОбработчикЗавершения, ВладелецПрисоединенныхФайлов, Форма, 2, ПараметрыДобавленияФайла);
		Иначе
			ПараметрыВыполнения.Действие = "ПросмотретьФайл";
			ВыполнитьДействиеСФайлом(ПараметрыВыполнения, ОбработчикЗавершения);
		КонецЕсли;
		
	ИначеЕсли СтрНачинаетсяС(ИмяКоманды, РаботаСФайламиКлиентСервер.ИмяКомандыСоздатьПоШаблону()) Тогда
		ДобавитьФайл(ОбработчикЗавершения, ВладелецПрисоединенныхФайлов, Форма, 1, ПараметрыДобавленияФайла);
	ИначеЕсли СтрНачинаетсяС(ИмяКоманды, РаботаСФайламиКлиентСервер.ИмяКомандыСканировать()) Тогда
		ДобавитьФайл(ОбработчикЗавершения, ВладелецПрисоединенныхФайлов, Форма, 3, ПараметрыДобавленияФайла);
	ИначеЕсли СтрНачинаетсяС(ИмяКоманды, РаботаСФайламиКлиентСервер.ИмяКомандыВыбратьФайл()) Тогда
		ПараметрыВыполнения.Действие = "ВыбратьФайл";
		ОткрытьФормуВыбораФайлов(ВладелецПрисоединенныхФайлов, Неопределено, Ложь, ОбработчикЗавершения);
	ИначеЕсли СтрНачинаетсяС(ИмяКоманды, РаботаСФайламиКлиентСервер.ИмяКомандыПросмотретьФайл()) Тогда
		ПараметрыВыполнения.Действие = "ПросмотретьФайл";
		ВыполнитьДействиеСФайлом(ПараметрыВыполнения, ОбработчикЗавершения);
	ИначеЕсли СтрНачинаетсяС(ИмяКоманды, РаботаСФайламиКлиентСервер.ИмяКомандыОчистить()) Тогда
		ОбновитьРеквизитХраненияПрисоединенногоФайла(Форма, ПараметрыВыполнения.НомерЭлемента, Неопределено);
	ИначеЕсли СтрНачинаетсяС(ИмяКоманды, РаботаСФайламиКлиентСервер.ИмяКомандыОткрытьФорму()) Тогда
		ПараметрыВыполнения.Действие = "ОткрытьФорму";
		ВыполнитьДействиеСФайлом(ПараметрыВыполнения, ОбработчикЗавершения);
	ИначеЕсли СтрНачинаетсяС(ИмяКоманды, РаботаСФайламиКлиентСервер.ИмяКомандыРедактироватьФайл()) Тогда
		ПараметрыВыполнения.Действие = "РедактироватьФайл";
		ВыполнитьДействиеСФайлом(ПараметрыВыполнения, ОбработчикЗавершения);
	ИначеЕсли СтрНачинаетсяС(ИмяКоманды, РаботаСФайламиКлиентСервер.ИмяКомандыПоместитьФайл()) Тогда
		ПараметрыВыполнения.Действие = "ПоместитьФайл";
		ВыполнитьДействиеСФайлом(ПараметрыВыполнения, ОбработчикЗавершения);
	ИначеЕсли СтрНачинаетсяС(ИмяКоманды, РаботаСФайламиКлиентСервер.ИмяКомандыОтменитьРедактирование()) Тогда
		ПараметрыВыполнения.Действие = "ОтменитьРедактирование";
		ВыполнитьДействиеСФайлом(ПараметрыВыполнения, ОбработчикЗавершения);
	КонецЕсли;
	
КонецПроцедуры

Процедура ПолеПредпросмотраНажатиеЗавершение(Форма, ВладелецПрисоединенныхФайлов, Элемент, СтандартнаяОбработка,
	Просмотр = Ложь, ТолькоОдинФайл = Ложь)
	
	СтандартнаяОбработка = Ложь;
	НомерЭлемента = СтрЗаменить(Элемент.Имя, "ПолеКартинкиПрисоединенногоФайла", "");
	ПараметрыВыполнения = ПараметрыКомандыУправления(Форма);
	ПараметрыВыполнения.НомерЭлемента = НомерЭлемента;
	
	ТипЧисло = Новый ОписаниеТипов("Число");
	НомерЭлемента = ТипЧисло.ПривестиЗначение(ПараметрыВыполнения.НомерЭлемента);
	ПараметрыРаботыСФайлом = Форма.ПараметрыРаботыСФайлами.ОписанияЭлементовФормы[НомерЭлемента];
	ПараметрыДобавленияФайла = Новый Структура;
	ПараметрыДобавленияФайла.Вставить("МаксимальныйРазмер", ПараметрыРаботыСФайлом.МаксимальныйРазмер);
	ПараметрыДобавленияФайла.Вставить("ФильтрДиалогаВыбора", ПараметрыРаботыСФайлом.ФильтрДиалогаВыбора);


	ПараметрыДобавленияФайла.Вставить("НеОткрыватьКарточку", Истина);
	РеквизитРазмещения = Неопределено;
	Если ПараметрыРаботыСФайлом.Свойство("ПутьКДаннымИзображения") И ЗначениеЗаполнено(ПараметрыРаботыСФайлом.ПутьКРеквизитуРазмещения) Тогда
		ПутьКРеквизитуРазмещения = ПараметрыРаботыСФайлом.ПутьКРеквизитуРазмещения;
		ЭлементыПути = СтрРазделить(ПутьКРеквизитуРазмещения, ".", Ложь);
		РеквизитРазмещения = ЭлементыПути[ЭлементыПути.ВГраница()];
	КонецЕсли;
	
	ПараметрыДобавленияИзображения = РаботаСФайламиСлужебныйВызовСервера.ПараметрыДобавленияИзображения(ВладелецПрисоединенныхФайлов, РеквизитРазмещения);
	Если Просмотр
		Или (Не ПараметрыДобавленияИзображения.ПравоДобавления И Не ПараметрыДобавленияИзображения.ПравоИзменения) Тогда
		
		ПараметрыВыполнения.Действие = "ПросмотретьФайл";
		ВыполнитьДействиеСФайлом(ПараметрыВыполнения, Неопределено);

	Иначе
		
		ОбработчикЗавершения = Новый ОписаниеОповещения("ЗавершениеВыполненияКомандыСОповещением",
			ЭтотОбъект, ПараметрыВыполнения);
		
		Если ТолькоОдинФайл Тогда
			
			ФайлыВладельца = ПараметрыДобавленияИзображения.ФайлыВладельца;
			Если ФайлыВладельца.КоличествоФайлов > 0 Тогда
				
				ДанныеФайла = ФайлыВладельца.ДанныеФайла; // См. РаботаСФайлами.ДанныеФайла
				ПараметрыВыполнения.Действие = "ЗаменитьФайл";
				ПараметрыВыполнения.Вставить("ФайлКартинки", ДанныеФайла.Ссылка);
				
				РаботаСФайламиСлужебныйКлиент.ОбновитьИзФайлаНаДискеСОповещением(ОбработчикЗавершения, ДанныеФайла,
					Форма.УникальныйИдентификатор, ПараметрыДобавленияФайла);
				
			Иначе
				ДобавитьФайл(ОбработчикЗавершения, ВладелецПрисоединенныхФайлов, Форма, 2, ПараметрыДобавленияФайла);
			КонецЕсли;
			
		Иначе
			ДобавитьФайл(ОбработчикЗавершения, ВладелецПрисоединенныхФайлов, Форма, 2, ПараметрыДобавленияФайла);
		КонецЕсли;
		
	КонецЕсли;
	
КонецПроцедуры

// Параметры:
//   РасширениеУстановлено - Булево
//   ДополнительныеПараметры - Структура:
//     * Элемент - ПолеФормы
//
Процедура ПолеПредпросмотраПеретаскиваниеЗавершение(РасширениеУстановлено, ДополнительныеПараметры) Экспорт
	
	Если Не РасширениеУстановлено Тогда
		Возврат;
	КонецЕсли;
	
	Форма = ДополнительныеПараметры.Форма;
	Элемент = ДополнительныеПараметры.Элемент;
	ПараметрыПеретаскивания = ДополнительныеПараметры.ПараметрыПеретаскивания;
	ВладелецПрисоединенныхФайлов = ДополнительныеПараметры.ВладелецПрисоединенныхФайлов;
	
	ПараметрыВыполнения = ПараметрыКомандыУправления(Форма);
	ПараметрыВыполнения.НомерЭлемента = СтрЗаменить(Элемент.Имя, "ПолеКартинкиПрисоединенногоФайла", "");
	
	ТипЧисло = Новый ОписаниеТипов("Число");
	НомерЭлемента = ТипЧисло.ПривестиЗначение(ПараметрыВыполнения.НомерЭлемента);
	Если ТипЗнч(ПараметрыПеретаскивания.Значение) = Тип("СсылкаНаФайл")
		И РаботаСФайламиСлужебныйВызовСервера.ЕстьПравоДоступа("Добавление", ВладелецПрисоединенныхФайлов) Тогда //@Access-right-2
		
		Файл = ПараметрыПеретаскивания.Значение.Файл;
		Если Файл = Неопределено Тогда
			Возврат;
		КонецЕсли;
		
		ПараметрыВыполнения.Действие = "ЗавершитьПеретаскивание";
		ОбработчикЗавершения = Новый ОписаниеОповещения("ЗавершениеВыполненияКомандыСОповещением",
			ЭтотОбъект, ПараметрыВыполнения);
		
		ПараметрыДобавления = Новый Структура;
		ПараметрыДобавления.Вставить("ОбработчикРезультата", ОбработчикЗавершения);
		ПараметрыДобавления.Вставить("ПолноеИмяФайла", Файл.ПолноеИмя);
		ПараметрыДобавления.Вставить("ВладелецФайла", ВладелецПрисоединенныхФайлов);
		ПараметрыДобавления.Вставить("ФормаВладелец", Форма);
		ПараметрыДобавления.Вставить("НеОткрыватьКарточкуПослеСозданияИзФайла", Истина);
		ПараметрыДобавления.Вставить("ИмяСоздаваемогоФайла", Файл.ИмяБезРасширения);
		ПараметрыДобавления.Вставить("МаксимальныйРазмер",
			Форма.ПараметрыРаботыСФайлами.ОписанияЭлементовФормы[НомерЭлемента].МаксимальныйРазмер);
		ПараметрыДобавления.Вставить("ФильтрДиалогаВыбора",
			Форма.ПараметрыРаботыСФайлами.ОписанияЭлементовФормы[НомерЭлемента].ФильтрДиалогаВыбора);
			
		РаботаСФайламиСлужебныйКлиент.ДобавитьИзФайловойСистемыСРасширением(ПараметрыДобавления);
		
	КонецЕсли;
	
КонецПроцедуры

Процедура ОбновитьРеквизитХраненияПрисоединенногоФайла(Форма, Знач НомерЭлемента, Файл)
	
	Если ТипЗнч(НомерЭлемента) = Тип("Строка") Тогда
		НомерЭлемента = Число(НомерЭлемента);
	КонецЕсли;
	
	ПутьКДанным = Форма.ПараметрыРаботыСФайлами.ОписанияЭлементовФормы[НомерЭлемента].ПутьКРеквизитуРазмещения;
	ЧастиПутиКДанным = СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок(ПутьКДанным, ".", Истина, Истина);
	
	Если ЧастиПутиКДанным.Количество() > 0 Тогда
		
		УровеньРасположенияРеквизита = ЧастиПутиКДанным.Количество();
		Если УровеньРасположенияРеквизита = 1 Тогда
			Форма[ЧастиПутиКДанным[0]] = Файл;
		ИначеЕсли УровеньРасположенияРеквизита = 2 Тогда
			Форма[ЧастиПутиКДанным[0]][ЧастиПутиКДанным[1]] = Файл;
		Иначе
			Возврат;
		КонецЕсли;
		
		ОбновитьОбластьПредпросмотра(Форма, НомерЭлемента, Файл);
		
		Форма.Модифицированность = Истина;
		
	КонецЕсли;
	
КонецПроцедуры

Процедура ОбновитьОбластьПредпросмотра(Форма, НомерЭлемента, Файл)
	
	Если ТипЗнч(НомерЭлемента) = Тип("Строка") Тогда
		НомерЭлементаЧислом = Число(НомерЭлемента);
		НомерЭлементаСтрокой = НомерЭлемента;
	Иначе
		НомерЭлементаЧислом = НомерЭлемента;
		НомерЭлементаСтрокой = Формат(НомерЭлемента, "ЧГ=;");
	КонецЕсли;
	
	ИмяРеквизита = Форма.ПараметрыРаботыСФайлами.ОписанияЭлементовФормы[НомерЭлементаЧислом].ПутьКДаннымИзображения;
	ЭлементКартинки = Форма.Элементы.Найти("ПолеКартинкиПрисоединенногоФайла" + НомерЭлементаСтрокой);
	ЭлементЗаголовка = Форма.Элементы.Найти("ЗаголовокПрисоединенногоФайла" + НомерЭлементаСтрокой);
	
	ПараметрыДанных = РаботаСФайламиКлиентСервер.ПараметрыДанныхФайла();
	ПараметрыДанных.ВызыватьИсключение = Ложь;
	ПараметрыДанных.ИдентификаторФормы = Форма.УникальныйИдентификатор;
	
	ДанныеОбновления = РаботаСФайламиСлужебныйВызовСервера.ДанныеОбновленияПоляИзображения(
		Файл, ПараметрыДанных);
		
	ДанныеФайла = ДанныеОбновления.ДанныеФайла;
	Если ЭлементКартинки <> Неопределено Тогда
		
		ТекстНевыбраннойКартинки = Форма.ПараметрыРаботыСФайлами.ОписанияЭлементовФормы[НомерЭлементаЧислом].ТекстНевыбраннойКартинки;
		Если ДанныеФайла = Неопределено Тогда
			Форма[ИмяРеквизита] = Неопределено;
			ЭлементКартинки.ТекстНевыбраннойКартинки = ТекстНевыбраннойКартинки;
		ИначеЕсли ДанныеОбновления.ФайлПоврежден Тогда
			Форма[ИмяРеквизита] = Неопределено;
			ЭлементКартинки.ТекстНевыбраннойКартинки = НСтр("ru = 'Изображение отсутствует'");
		Иначе
			Форма[ИмяРеквизита] = ДанныеФайла.СсылкаНаДвоичныеДанныеФайла;
			ЭлементКартинки.ТекстНевыбраннойКартинки = ТекстНевыбраннойКартинки;
		КонецЕсли;
		
		ЭлементКартинки.ЦветТекста = ДанныеОбновления.ЦветТекста;
		
	КонецЕсли;
	
	Если ЭлементЗаголовка <> Неопределено Тогда
		
		Если ДанныеФайла = Неопределено Тогда
			ЭлементЗаголовка.Заголовок = НСтр("ru = 'загрузить'");
			ЭлементЗаголовка.ОтображениеПодсказки = ОтображениеПодсказки.Нет;
		Иначе
			ЭлементЗаголовка.Заголовок = ДанныеФайла.ИмяФайла;
			ЭлементЗаголовка.ОтображениеПодсказки = ОтображениеПодсказки.Авто;
		КонецЕсли;
		
	КонецЕсли;
	
КонецПроцедуры

Процедура ВыполнитьДействиеСФайлом(ПараметрыВыполнения, ОбработчикЗавершения)
	
	Форма = ПараметрыВыполнения.Форма;
	Размещение = ЗначениеПараметраПрисоединенногоФайла(Форма, Число(ПараметрыВыполнения.НомерЭлемента), "ПутьКРеквизитуРазмещения");
	Если ЗначениеЗаполнено(Размещение) Тогда
		
		Если ПараметрыВыполнения.Действие = "ПросмотретьФайл" Тогда
			ДанныеФайла = РаботаСФайламиСлужебныйВызовСервера.ДанныеФайлаДляОткрытия(Размещение, Неопределено, Форма.УникальныйИдентификатор);
			ОткрытьФайл(ДанныеФайла);
		ИначеЕсли ПараметрыВыполнения.Действие = "ОткрытьФорму" Тогда
			ОткрытьФормуФайла(Размещение);
		ИначеЕсли ПараметрыВыполнения.Действие = "РедактироватьФайл" Тогда
			РаботаСФайламиСлужебныйКлиент.РедактироватьСОповещением(ОбработчикЗавершения, Размещение);
		ИначеЕсли ПараметрыВыполнения.Действие = "ПоместитьФайл" Тогда
			
			ПараметрыОбновленияФайла = РаботаСФайламиСлужебныйКлиент.ПараметрыОбновленияФайла(ОбработчикЗавершения,
				Размещение, Форма.УникальныйИдентификатор);
			ПараметрыОбновленияФайла.Вставить("СоздатьНовуюВерсию", Ложь);
			РаботаСФайламиСлужебныйКлиент.ЗакончитьРедактированиеСОповещением(ПараметрыОбновленияФайла);
			
		ИначеЕсли ПараметрыВыполнения.Действие = "ОтменитьРедактирование" Тогда
			
			МассивФайлов = Новый Массив;
			МассивФайлов.Добавить(Размещение);
			
			РаботаСФайламиСлужебныйВызовСервера.ОсвободитьФайлы(МассивФайлов);
			ЗавершениеВыполненияКомандыСОповещением(Неопределено, ПараметрыВыполнения);
			
		КонецЕсли;
		
	КонецЕсли;
	
КонецПроцедуры

Процедура ЗавершениеВыполненияКомандыСОповещением(Результат, ДополнительныеПараметры) Экспорт
	
	Если ДополнительныеПараметры.Действие = "ЗаменитьФайл" Тогда
		
		ОбновитьОбластьПредпросмотра(ДополнительныеПараметры.Форма, ДополнительныеПараметры.НомерЭлемента,
			ДополнительныеПараметры.ФайлКартинки);
		
	ИначеЕсли (ДополнительныеПараметры.Действие = "ЗагрузитьФайл"
		ИЛИ ДополнительныеПараметры.Действие = "ЗавершитьПеретаскивание")
		И Результат <> Неопределено
		И Результат.ФайлДобавлен Тогда
		
		ОбновитьРеквизитХраненияПрисоединенногоФайла(ДополнительныеПараметры.Форма, ДополнительныеПараметры.НомерЭлемента,
			Результат.ФайлСсылка);
		
	ИначеЕсли ДополнительныеПараметры.Действие = "ВыбратьФайл"
		И Результат <> Неопределено Тогда
		
		ОбновитьРеквизитХраненияПрисоединенногоФайла(ДополнительныеПараметры.Форма, ДополнительныеПараметры.НомерЭлемента,
			Результат);
		
	ИначеЕсли ДополнительныеПараметры.Действие = "РедактироватьФайл" Тогда
		ИзменитьДоступностьКнопок(ДополнительныеПараметры.Форма, ДополнительныеПараметры.НомерЭлемента, Истина);
	ИначеЕсли ДополнительныеПараметры.Действие = "ПоместитьФайл"
		Или ДополнительныеПараметры.Действие = "ОтменитьРедактирование" Тогда
		ИзменитьДоступностьКнопок(ДополнительныеПараметры.Форма, ДополнительныеПараметры.НомерЭлемента, Ложь);
	КонецЕсли;
	
КонецПроцедуры

// Параметры:
//
// Форма - ФормаКлиентскогоПриложения
//
Процедура ИзменитьДоступностьКнопок(Форма, НомерЭлемента, НачалоРедактирования)
	
	ПрефиксКоманды                   = РаботаСФайламиКлиентСервер.ПрефиксКоманд();
	ИмяКомандыПоместитьФайл          = РаботаСФайламиКлиентСервер.ИмяКомандыПоместитьФайл();
	ИмяКомандыОтменитьРедактирование = РаботаСФайламиКлиентСервер.ИмяКомандыОтменитьРедактирование();
	ИмяКомандыРедактироватьФайл      = РаботаСФайламиКлиентСервер.ИмяКомандыРедактироватьФайл();
	
	Кнопки = Новый СписокЗначений;
	Кнопки.Добавить(ПрефиксКоманды + ИмяКомандыПоместитьФайл + НомерЭлемента,, НачалоРедактирования);
	Кнопки.Добавить(ПрефиксКоманды + ИмяКомандыОтменитьРедактирование + НомерЭлемента,, НачалоРедактирования);
	Кнопки.Добавить(ПрефиксКоманды + ИмяКомандыРедактироватьФайл + НомерЭлемента,, Не НачалоРедактирования);
	Кнопки.Добавить(ИмяКомандыПоместитьФайл + РаботаСФайламиКлиентСервер.ИмяДополнительнойКомандыИзКонтекстногоМеню() + НомерЭлемента,, НачалоРедактирования);
	Кнопки.Добавить(ИмяКомандыОтменитьРедактирование + РаботаСФайламиКлиентСервер.ИмяДополнительнойКомандыИзКонтекстногоМеню() + НомерЭлемента,, НачалоРедактирования);
	Кнопки.Добавить(ИмяКомандыРедактироватьФайл + РаботаСФайламиКлиентСервер.ИмяДополнительнойКомандыИзКонтекстногоМеню() + НомерЭлемента,, Не НачалоРедактирования);
	
	Элементы = Форма.Элементы;
	Для Каждого Кнопка Из Кнопки Цикл
		
		КнопкаФормы = Элементы.Найти(Кнопка.Значение);
		Если КнопкаФормы <> Неопределено Тогда
			КнопкаФормы.Доступность = Кнопка.Пометка;
		КонецЕсли;
		
	КонецЦикла;
		
КонецПроцедуры

Процедура ИзменитьВидимостьДополнительныхКоманд(Форма)
	
	Попытка
		ЕстьПараметрыРаботыСФайлами = ТипЗнч(Форма["ПараметрыРаботыСФайлами"]) = Тип("ФиксированнаяСтруктура");
	Исключение
		// Реквизита ПараметрыРаботыСФайлами нет на форме, либо он не проинициализирован.
		ЕстьПараметрыРаботыСФайлами = Ложь;
	КонецПопытки;
	
	Если Не ЕстьПараметрыРаботыСФайлами Тогда
		Возврат;
	КонецЕсли;
	
	ПрефиксКоманды = РаботаСФайламиКлиентСервер.ПрефиксКоманд();
	
	Для ИндексЭлемента = 0 По Форма.ПараметрыРаботыСФайлами.ОписанияЭлементовФормы.ВГраница() Цикл
		
		ПодменюКоманд                 = Форма.Элементы.Найти("ПодменюДобавленияФайла" + ИндексЭлемента);
		КнопкаКомандыВыбрать          = Форма.Элементы.Найти(ПрефиксКоманды + РаботаСФайламиКлиентСервер.ИмяКомандыВыбратьФайл() + ИндексЭлемента);
		КнопкаКомандыВыбрать          = Форма.Элементы.Найти(ПрефиксКоманды + РаботаСФайламиКлиентСервер.ИмяКомандыВыбратьФайл() + ИндексЭлемента);
		КнопкаКомандыЗагрузить        = Форма.Элементы.Найти(ПрефиксКоманды + РаботаСФайламиКлиентСервер.ИмяКомандыЗагрузитьФайл() + ИндексЭлемента);
		КнопкаКомандыСканировать      = Форма.Элементы.Найти(ПрефиксКоманды + РаботаСФайламиКлиентСервер.ИмяКомандыСканировать() + ИндексЭлемента);
		КнопкаКомандыСоздатьИзШаблона = Форма.Элементы.Найти(ПрефиксКоманды + РаботаСФайламиКлиентСервер.ИмяКомандыСоздатьПоШаблону() + ИндексЭлемента);
		
		Если КнопкаКомандыСканировать <> Неопределено Тогда
			КнопкаКомандыСканировать.Видимость = Ложь;
			КнопкаКомандыСканироватьИзКонтекстногоМеню = Форма.Элементы.Найти(РаботаСФайламиКлиентСервер.ПрефиксКоманд()
				+ РаботаСФайламиКлиентСервер.ИмяКомандыСканировать() + РаботаСФайламиКлиентСервер.ИмяДополнительнойКомандыИзКонтекстногоМеню() + ИндексЭлемента);
			Если КнопкаКомандыСканироватьИзКонтекстногоМеню <> Неопределено Тогда
				КнопкаКомандыСканироватьИзКонтекстногоМеню.Видимость = Ложь;
			КонецЕсли;
		КонецЕсли;
		
		Если КнопкаКомандыСоздатьИзШаблона <> Неопределено Тогда
			КнопкаКомандыСоздатьИзШаблона.Видимость = Ложь;
			КнопкаКомандыСоздатьИзШаблонаИзКонтекстногоМеню = Форма.Элементы.Найти(РаботаСФайламиКлиентСервер.ПрефиксКоманд() 
				+ РаботаСФайламиКлиентСервер.ИмяКомандыСканировать() + РаботаСФайламиКлиентСервер.ИмяДополнительнойКомандыИзКонтекстногоМеню() + ИндексЭлемента);
			Если КнопкаКомандыСоздатьИзШаблонаИзКонтекстногоМеню <> Неопределено Тогда
				КнопкаКомандыСоздатьИзШаблонаИзКонтекстногоМеню.Видимость = Ложь;
			КонецЕсли;
		КонецЕсли;
		
		ВидимостьПодменю = Ложь;
		Если ПодменюКоманд <> Неопределено Тогда
			ВидимостьПодменю = КнопкаКомандыВыбрать <> Неопределено;
			ПодменюКоманд.Видимость = ВидимостьПодменю;
		КонецЕсли;
		
		Если КнопкаКомандыЗагрузить <> Неопределено Тогда
			КнопкаКомандыЗагрузить.Видимость = Не ВидимостьПодменю;
		КонецЕсли;
		
	КонецЦикла;
	
КонецПроцедуры

Процедура НачатьПроверкуНаличияПрограммыКонвертации(ПутьКПрограммеКонвертации, ОповещениеРезультата) Экспорт
	
	КомандыСистемы = """" + ПутьКПрограммеКонвертации + """ -version";
	
	ПараметрыЗапускаПрограммы = ФайловаяСистемаКлиент.ПараметрыЗапускаПрограммы();
	ПараметрыЗапускаПрограммы.ДождатьсяЗавершения = Истина;
	ПараметрыЗапускаПрограммы.ПолучитьПотокОшибок = Истина;
	ПараметрыЗапускаПрограммы.ПолучитьПотокВывода = Истина;
	
	ПараметрыЗапускаПрограммы.Оповещение = ОповещениеРезультата;
	ФайловаяСистемаКлиент.ЗапуститьПрограмму(КомандыСистемы, ПараметрыЗапускаПрограммы);
КонецПроцедуры

Функция СобытиеЖурналаРегистрации()
	
	Возврат НСтр("ru = 'Файлы'", ОбщегоНазначенияКлиент.КодОсновногоЯзыка());
	
КонецФункции

#КонецОбласти

#КонецОбласти
